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