b4006a8812e483da7331210537175e3647a0c175
[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,myflags = 0;
811         struct ast_format *f;
812         struct ast_filestream *fs=NULL;
813         char *fn;
814         if (ast_mutex_lock(&formatlock)) {
815                 ast_log(LOG_WARNING, "Unable to lock format list\n");
816                 return NULL;
817         }
818         f = formats;
819         while(f) {
820                 if (exts_compare(f->exts, type)) {
821                         fn = build_filename(filename, type);
822                         fd = open(fn, flags | myflags);
823                         if (fd >= 0) {
824                                 errno = 0;
825                                 if ((fs = f->open(fd))) {
826                                         fs->trans = NULL;
827                                         fs->fmt = f;
828                                         fs->flags = flags;
829                                         fs->mode = mode;
830                                         fs->filename = strdup(filename);
831                                         fs->vfs = NULL;
832                                 } else {
833                                         ast_log(LOG_WARNING, "Unable to open %s\n", fn);
834                                         close(fd);
835                                         unlink(fn);
836                                 }
837                         } else if (errno != EEXIST)
838                                 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
839                         free(fn);
840                         break;
841                 }
842                 f = f->next;
843         }
844         ast_mutex_unlock(&formatlock);
845         if (!f) 
846                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
847         return fs;
848 }
849
850 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
851 {
852         int fd,myflags = 0;
853         struct ast_format *f;
854         struct ast_filestream *fs=NULL;
855         char *fn,*orig_fn=NULL;
856         char *buf=NULL;
857         size_t size = 0;
858
859         if (ast_mutex_lock(&formatlock)) {
860                 ast_log(LOG_WARNING, "Unable to lock format list\n");
861                 return NULL;
862         }
863         /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
864         if (flags & O_APPEND) { 
865                 /* We really can't use O_APPEND as it will break WAV header updates */
866                 flags &= ~O_APPEND;
867         } else {
868                 myflags = O_TRUNC;
869         }
870         
871         myflags |= O_WRONLY | O_CREAT;
872
873         f = formats;
874         while(f) {
875                 if (exts_compare(f->exts, type)) {
876                         fn = build_filename(filename, type);
877                         fd = open(fn, flags | myflags, mode);
878                         
879                         if (option_cache_record_files && fd >= 0) {
880                                 close(fd);
881                                 /*
882                                    We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
883                                    What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
884                                 */
885                                 orig_fn = ast_strdupa(fn); 
886                                 for (size=0;size<strlen(fn);size++) {
887                                         if (fn[size] == '/')
888                                                 fn[size] = '_';
889                                 }
890
891                                 size += (strlen(record_cache_dir) + 10);
892                                 buf = alloca(size);
893                                 memset(buf, 0, size);
894                                 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
895                                 free(fn);
896                                 fn=buf;
897                                 fd = open(fn, flags | myflags, mode);
898                         }
899                         if (fd >= 0) {
900                                 errno = 0;
901                                 if ((fs = f->rewrite(fd, comment))) {
902                                         fs->trans = NULL;
903                                         fs->fmt = f;
904                                         fs->flags = flags;
905                                         fs->mode = mode;
906                                         if (option_cache_record_files) {
907                                                 fs->realfilename = build_filename(filename, type);
908                                                 fs->filename = strdup(fn);
909                                         } else {
910                                                 fs->realfilename = NULL;
911                                                 fs->filename = strdup(filename);
912                                         }
913                                         fs->vfs = NULL;
914                                 } else {
915                                         ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
916                                         close(fd);
917                                         unlink(fn);
918                                         if (orig_fn)
919                                                 unlink(orig_fn);
920                                 }
921                         } else if (errno != EEXIST) {
922                                 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
923                                 if (orig_fn)
924                                         unlink(orig_fn);
925                         }
926                         if (!buf) /* if buf != NULL then fn is already free and pointing to it */
927                                 free(fn);
928
929                         break;
930                 }
931                 f = f->next;
932         }
933         ast_mutex_unlock(&formatlock);
934         if (!f) 
935                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
936         return fs;
937 }
938
939 int ast_waitstream(struct ast_channel *c, const char *breakon)
940 {
941         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
942         int res;
943         struct ast_frame *fr;
944         if (!breakon) breakon = "";
945         while(c->stream) {
946                 res = ast_sched_wait(c->sched);
947                 if ((res < 0) && !c->timingfunc) {
948                         ast_stopstream(c);
949                         break;
950                 }
951                 if (res < 0)
952                         res = 1000;
953                 res = ast_waitfor(c, res);
954                 if (res < 0) {
955                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
956                         return res;
957                 } else if (res > 0) {
958                         fr = ast_read(c);
959                         if (!fr) {
960 #if 0
961                                 ast_log(LOG_DEBUG, "Got hung up\n");
962 #endif
963                                 return -1;
964                         }
965                         
966                         switch(fr->frametype) {
967                         case AST_FRAME_DTMF:
968                                 res = fr->subclass;
969                                 if (strchr(breakon, res)) {
970                                         ast_frfree(fr);
971                                         return res;
972                                 }
973                                 break;
974                         case AST_FRAME_CONTROL:
975                                 switch(fr->subclass) {
976                                 case AST_CONTROL_HANGUP:
977                                         ast_frfree(fr);
978                                         return -1;
979                                 case AST_CONTROL_RINGING:
980                                 case AST_CONTROL_ANSWER:
981                                         /* Unimportant */
982                                         break;
983                                 default:
984                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
985                                 }
986                         }
987                         /* Ignore */
988                         ast_frfree(fr);
989                 }
990                 ast_sched_runq(c->sched);
991         }
992         return (c->_softhangup ? -1 : 0);
993 }
994
995 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
996 {
997         int res;
998         struct ast_frame *fr;
999
1000         if (!breakon)
1001                         breakon = "";
1002         if (!forward)
1003                         forward = "";
1004         if (!rewind)
1005                         rewind = "";
1006         
1007         while(c->stream) {
1008                 res = ast_sched_wait(c->sched);
1009                 if ((res < 0) && !c->timingfunc) {
1010                         ast_stopstream(c);
1011                         break;
1012                 }
1013                 if (res < 0)
1014                         res = 1000;
1015                 res = ast_waitfor(c, res);
1016                 if (res < 0) {
1017                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1018                         return res;
1019                 } else
1020                 if (res > 0) {
1021                         fr = ast_read(c);
1022                         if (!fr) {
1023 #if 0
1024                                 ast_log(LOG_DEBUG, "Got hung up\n");
1025 #endif
1026                                 return -1;
1027                         }
1028                         
1029                         switch(fr->frametype) {
1030                         case AST_FRAME_DTMF:
1031                                 res = fr->subclass;
1032                                 if (strchr(forward,res)) {
1033                                         ast_stream_fastforward(c->stream, ms);
1034                                 } else if (strchr(rewind,res)) {
1035                                         ast_stream_rewind(c->stream, ms);
1036                                 } else if (strchr(breakon, res)) {
1037                                         ast_frfree(fr);
1038                                         return res;
1039                                 }                                       
1040                                 break;
1041                         case AST_FRAME_CONTROL:
1042                                 switch(fr->subclass) {
1043                                 case AST_CONTROL_HANGUP:
1044                                         ast_frfree(fr);
1045                                         return -1;
1046                                 case AST_CONTROL_RINGING:
1047                                 case AST_CONTROL_ANSWER:
1048                                         /* Unimportant */
1049                                         break;
1050                                 default:
1051                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1052                                 }
1053                         }
1054                         /* Ignore */
1055                         ast_frfree(fr);
1056                 } else
1057                         ast_sched_runq(c->sched);
1058         
1059                 
1060         }
1061         return (c->_softhangup ? -1 : 0);
1062 }
1063
1064 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1065 {
1066         int res;
1067         int ms;
1068         int outfd;
1069         struct ast_frame *fr;
1070         struct ast_channel *rchan;
1071
1072         if (!breakon)
1073                 breakon = "";
1074         
1075         while(c->stream) {
1076                 ms = ast_sched_wait(c->sched);
1077                 if ((ms < 0) && !c->timingfunc) {
1078                         ast_stopstream(c);
1079                         break;
1080                 }
1081                 if (ms < 0)
1082                         ms = 1000;
1083                 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1084                 if (!rchan && (outfd < 0) && (ms)) {
1085                         /* Continue */
1086                         if (errno == EINTR)
1087                                 continue;
1088                         ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1089                         return -1;
1090                 } else if (outfd > -1) {
1091                         /* The FD we were watching has something waiting */
1092                         return 1;
1093                 } else if (rchan) {
1094                         fr = ast_read(c);
1095                         if (!fr) {
1096 #if 0
1097                                 ast_log(LOG_DEBUG, "Got hung up\n");
1098 #endif
1099                                 return -1;
1100                         }
1101                         
1102                         switch(fr->frametype) {
1103                         case AST_FRAME_DTMF:
1104                                 res = fr->subclass;
1105                                 if (strchr(breakon, res)) {
1106                                         ast_frfree(fr);
1107                                         return res;
1108                                 }
1109                                 break;
1110                         case AST_FRAME_CONTROL:
1111                                 switch(fr->subclass) {
1112                                 case AST_CONTROL_HANGUP:
1113                                         ast_frfree(fr);
1114                                         return -1;
1115                                 case AST_CONTROL_RINGING:
1116                                 case AST_CONTROL_ANSWER:
1117                                         /* Unimportant */
1118                                         break;
1119                                 default:
1120                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1121                                 }
1122                         case AST_FRAME_VOICE:
1123                                 /* Write audio if appropriate */
1124                                 if (audiofd > -1)
1125                                         write(audiofd, fr->data, fr->datalen);
1126                         }
1127                         /* Ignore */
1128                         ast_frfree(fr);
1129                 }
1130                 ast_sched_runq(c->sched);
1131         }
1132         return (c->_softhangup ? -1 : 0);
1133 }
1134
1135 static int show_file_formats(int fd, int argc, char *argv[])
1136 {
1137 #define FORMAT "%-10s %-10s %-20s\n"
1138 #define FORMAT2 "%-10s %-10s %-20s\n"
1139         struct ast_format *f;
1140         if (argc != 3)
1141                 return RESULT_SHOWUSAGE;
1142         ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1143                 
1144         if (ast_mutex_lock(&formatlock)) {
1145                 ast_log(LOG_WARNING, "Unable to lock format list\n");
1146                 return -1;
1147         }
1148
1149         f = formats;
1150         while(f) {
1151                 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1152                 f = f->next;
1153         };
1154         ast_mutex_unlock(&formatlock);
1155         return RESULT_SUCCESS;
1156 }
1157
1158 struct ast_cli_entry show_file =
1159 {
1160         { "show", "file", "formats" },
1161         show_file_formats,
1162         "Displays file formats",
1163         "Usage: show file formats\n"
1164         "       displays currently registered file formats (if any)\n"
1165 };
1166
1167 int ast_file_init(void)
1168 {
1169         ast_cli_register(&show_file);
1170         return 0;
1171 }