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