issue #5622
[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 (option_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                         } else {
959                                 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
960                                 close(fd);
961                                 if (orig_fn) {
962                                         unlink(fn);
963                                         unlink(orig_fn);
964                                 }
965                         }
966                 } else if (errno != EEXIST) {
967                         ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
968                         if (orig_fn)
969                                 unlink(orig_fn);
970                 }
971                 /* if buf != NULL then fn is already free and pointing to it */
972                 if (!buf)
973                         free(fn);
974         }
975
976         ast_mutex_unlock(&formatlock);
977         if (!fs)
978                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
979
980         return fs;
981 }
982
983 int ast_waitstream(struct ast_channel *c, const char *breakon)
984 {
985         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
986         int res;
987         struct ast_frame *fr;
988         if (!breakon) breakon = "";
989         while(c->stream) {
990                 res = ast_sched_wait(c->sched);
991                 if ((res < 0) && !c->timingfunc) {
992                         ast_stopstream(c);
993                         break;
994                 }
995                 if (res < 0)
996                         res = 1000;
997                 res = ast_waitfor(c, res);
998                 if (res < 0) {
999                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1000                         return res;
1001                 } else if (res > 0) {
1002                         fr = ast_read(c);
1003                         if (!fr) {
1004 #if 0
1005                                 ast_log(LOG_DEBUG, "Got hung up\n");
1006 #endif
1007                                 return -1;
1008                         }
1009                         
1010                         switch(fr->frametype) {
1011                         case AST_FRAME_DTMF:
1012                                 res = fr->subclass;
1013                                 if (strchr(breakon, res)) {
1014                                         ast_frfree(fr);
1015                                         return res;
1016                                 }
1017                                 break;
1018                         case AST_FRAME_CONTROL:
1019                                 switch(fr->subclass) {
1020                                 case AST_CONTROL_HANGUP:
1021                                         ast_frfree(fr);
1022                                         return -1;
1023                                 case AST_CONTROL_RINGING:
1024                                 case AST_CONTROL_ANSWER:
1025                                 case AST_CONTROL_VIDUPDATE:
1026                                         /* Unimportant */
1027                                         break;
1028                                 default:
1029                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1030                                 }
1031                         }
1032                         /* Ignore */
1033                         ast_frfree(fr);
1034                 }
1035                 ast_sched_runq(c->sched);
1036         }
1037         return (c->_softhangup ? -1 : 0);
1038 }
1039
1040 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
1041 {
1042         int res;
1043         struct ast_frame *fr;
1044
1045         if (!breakon)
1046                         breakon = "";
1047         if (!forward)
1048                         forward = "";
1049         if (!rewind)
1050                         rewind = "";
1051         
1052         while(c->stream) {
1053                 res = ast_sched_wait(c->sched);
1054                 if ((res < 0) && !c->timingfunc) {
1055                         ast_stopstream(c);
1056                         break;
1057                 }
1058                 if (res < 0)
1059                         res = 1000;
1060                 res = ast_waitfor(c, res);
1061                 if (res < 0) {
1062                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1063                         return res;
1064                 } else
1065                 if (res > 0) {
1066                         fr = ast_read(c);
1067                         if (!fr) {
1068 #if 0
1069                                 ast_log(LOG_DEBUG, "Got hung up\n");
1070 #endif
1071                                 return -1;
1072                         }
1073                         
1074                         switch(fr->frametype) {
1075                         case AST_FRAME_DTMF:
1076                                 res = fr->subclass;
1077                                 if (strchr(forward,res)) {
1078                                         ast_stream_fastforward(c->stream, ms);
1079                                 } else if (strchr(rewind,res)) {
1080                                         ast_stream_rewind(c->stream, ms);
1081                                 } else if (strchr(breakon, res)) {
1082                                         ast_frfree(fr);
1083                                         return res;
1084                                 }                                       
1085                                 break;
1086                         case AST_FRAME_CONTROL:
1087                                 switch(fr->subclass) {
1088                                 case AST_CONTROL_HANGUP:
1089                                         ast_frfree(fr);
1090                                         return -1;
1091                                 case AST_CONTROL_RINGING:
1092                                 case AST_CONTROL_ANSWER:
1093                                         /* Unimportant */
1094                                         break;
1095                                 default:
1096                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1097                                 }
1098                         }
1099                         /* Ignore */
1100                         ast_frfree(fr);
1101                 } else
1102                         ast_sched_runq(c->sched);
1103         
1104                 
1105         }
1106         return (c->_softhangup ? -1 : 0);
1107 }
1108
1109 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1110 {
1111         int res;
1112         int ms;
1113         int outfd;
1114         struct ast_frame *fr;
1115         struct ast_channel *rchan;
1116
1117         if (!breakon)
1118                 breakon = "";
1119         
1120         while(c->stream) {
1121                 ms = ast_sched_wait(c->sched);
1122                 if ((ms < 0) && !c->timingfunc) {
1123                         ast_stopstream(c);
1124                         break;
1125                 }
1126                 if (ms < 0)
1127                         ms = 1000;
1128                 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1129                 if (!rchan && (outfd < 0) && (ms)) {
1130                         /* Continue */
1131                         if (errno == EINTR)
1132                                 continue;
1133                         ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1134                         return -1;
1135                 } else if (outfd > -1) {
1136                         /* The FD we were watching has something waiting */
1137                         return 1;
1138                 } else if (rchan) {
1139                         fr = ast_read(c);
1140                         if (!fr) {
1141 #if 0
1142                                 ast_log(LOG_DEBUG, "Got hung up\n");
1143 #endif
1144                                 return -1;
1145                         }
1146                         
1147                         switch(fr->frametype) {
1148                         case AST_FRAME_DTMF:
1149                                 res = fr->subclass;
1150                                 if (strchr(breakon, res)) {
1151                                         ast_frfree(fr);
1152                                         return res;
1153                                 }
1154                                 break;
1155                         case AST_FRAME_CONTROL:
1156                                 switch(fr->subclass) {
1157                                 case AST_CONTROL_HANGUP:
1158                                         ast_frfree(fr);
1159                                         return -1;
1160                                 case AST_CONTROL_RINGING:
1161                                 case AST_CONTROL_ANSWER:
1162                                         /* Unimportant */
1163                                         break;
1164                                 default:
1165                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1166                                 }
1167                         case AST_FRAME_VOICE:
1168                                 /* Write audio if appropriate */
1169                                 if (audiofd > -1)
1170                                         write(audiofd, fr->data, fr->datalen);
1171                         }
1172                         /* Ignore */
1173                         ast_frfree(fr);
1174                 }
1175                 ast_sched_runq(c->sched);
1176         }
1177         return (c->_softhangup ? -1 : 0);
1178 }
1179
1180 int ast_waitstream_exten(struct ast_channel *c, const char *context)
1181 {
1182         /* Waitstream, with return in the case of a valid 1 digit extension */
1183         /* in the current or specified context being pressed */
1184         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
1185         int res;
1186         struct ast_frame *fr;
1187         char exten[AST_MAX_EXTENSION];
1188
1189         if (!context) context = c->context;
1190         while(c->stream) {
1191                 res = ast_sched_wait(c->sched);
1192                 if ((res < 0) && !c->timingfunc) {
1193                         ast_stopstream(c);
1194                         break;
1195                 }
1196                 if (res < 0)
1197                         res = 1000;
1198                 res = ast_waitfor(c, res);
1199                 if (res < 0) {
1200                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1201                         return res;
1202                 } else if (res > 0) {
1203                         fr = ast_read(c);
1204                         if (!fr) {
1205 #if 0
1206                                 ast_log(LOG_DEBUG, "Got hung up\n");
1207 #endif
1208                                 return -1;
1209                         }
1210                         
1211                         switch(fr->frametype) {
1212                         case AST_FRAME_DTMF:
1213                                 res = fr->subclass;
1214                                 snprintf(exten, sizeof(exten), "%c", res);
1215                                 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
1216                                         ast_frfree(fr);
1217                                         return res;
1218                                 }
1219                                 break;
1220                         case AST_FRAME_CONTROL:
1221                                 switch(fr->subclass) {
1222                                 case AST_CONTROL_HANGUP:
1223                                         ast_frfree(fr);
1224                                         return -1;
1225                                 case AST_CONTROL_RINGING:
1226                                 case AST_CONTROL_ANSWER:
1227                                         /* Unimportant */
1228                                         break;
1229                                 default:
1230                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1231                                 }
1232                         }
1233                         /* Ignore */
1234                         ast_frfree(fr);
1235                 }
1236                 ast_sched_runq(c->sched);
1237         }
1238         return (c->_softhangup ? -1 : 0);
1239 }
1240
1241 static int show_file_formats(int fd, int argc, char *argv[])
1242 {
1243 #define FORMAT "%-10s %-10s %-20s\n"
1244 #define FORMAT2 "%-10s %-10s %-20s\n"
1245         struct ast_format *f;
1246         int count_fmt = 0;
1247
1248         if (argc != 3)
1249                 return RESULT_SHOWUSAGE;
1250         ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1251                 
1252         if (ast_mutex_lock(&formatlock)) {
1253                 ast_log(LOG_WARNING, "Unable to lock format list\n");
1254                 return -1;
1255         }
1256
1257         f = formats;
1258         while(f) {
1259                 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1260                 f = f->next;
1261                 count_fmt++;
1262         };
1263         ast_mutex_unlock(&formatlock);
1264         ast_cli(fd, "%d file formats registered.\n", count_fmt);
1265         return RESULT_SUCCESS;
1266 #undef FORMAT
1267 #undef FORMAT2
1268         
1269 }
1270
1271 struct ast_cli_entry show_file =
1272 {
1273         { "show", "file", "formats" },
1274         show_file_formats,
1275         "Displays file formats",
1276         "Usage: show file formats\n"
1277         "       displays currently registered file formats (if any)\n"
1278 };
1279
1280 int ast_file_init(void)
1281 {
1282         ast_cli_register(&show_file);
1283         return 0;
1284 }