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