Use FILE * instead of fd for files to support buffering
[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 /*
20  *
21  * 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 (preflang && !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 (preflang && !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 (preflang && !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         FILE *bfile;
874         struct ast_format *f;
875         struct ast_filestream *fs = NULL;
876         char *fn, *orig_fn = NULL;
877         char *buf = NULL;
878         size_t size = 0;
879
880         if (ast_mutex_lock(&formatlock)) {
881                 ast_log(LOG_WARNING, "Unable to lock format list\n");
882                 return NULL;
883         }
884
885         /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
886         if (flags & O_APPEND) { 
887                 /* We really can't use O_APPEND as it will break WAV header updates */
888                 flags &= ~O_APPEND;
889         } else {
890                 myflags = O_TRUNC;
891         }
892         
893         myflags |= O_WRONLY | O_CREAT;
894
895         for (f = formats; f && !fs; f = f->next) {
896                 if (!exts_compare(f->exts, type))
897                         continue;
898
899                 fn = build_filename(filename, type);
900                 fd = open(fn, flags | myflags, mode);
901                 if (fd > -1) {
902                         /* fdopen() the resulting file stream */
903                         bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
904                         if (!bfile) {
905                                 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
906                                 close(fd);
907                                 fd = -1;
908                         }
909                 }
910                 
911                 if (option_cache_record_files && fd >= 0) {
912                         char *c;
913
914                         fclose(bfile);
915                         /*
916                           We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
917                           What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
918                         */
919                         orig_fn = ast_strdupa(fn);
920                         for (c = fn; *c; c++)
921                                 if (*c == '/')
922                                         *c = '_';
923
924                         size = strlen(fn) + strlen(record_cache_dir) + 2;
925                         buf = alloca(size);
926                         memset(buf, 0, size);
927                         snprintf(buf, size, "%s/%s", record_cache_dir, fn);
928                         free(fn);
929                         fn = buf;
930                         fd = open(fn, flags | myflags, mode);
931                         if (fd > -1) {
932                                 /* fdopen() the resulting file stream */
933                                 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
934                                 if (!bfile) {
935                                         ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
936                                         close(fd);
937                                         fd = -1;
938                                 }
939                         }
940                 }
941                 if (fd >= 0) {
942                         errno = 0;
943
944                         if ((fs = f->rewrite(bfile, comment))) {
945                                 fs->trans = NULL;
946                                 fs->fmt = f;
947                                 fs->flags = flags;
948                                 fs->mode = mode;
949                                 if (orig_fn) {
950                                         fs->realfilename = strdup(orig_fn);
951                                         fs->filename = strdup(fn);
952                                 } else {
953                                         fs->realfilename = NULL;
954                                         fs->filename = strdup(filename);
955                                 }
956                                 fs->vfs = NULL;
957                         } else {
958                                 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
959                                 close(fd);
960                                 if (orig_fn) {
961                                         unlink(fn);
962                                         unlink(orig_fn);
963                                 }
964                         }
965                 } else if (errno != EEXIST) {
966                         ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
967                         if (orig_fn)
968                                 unlink(orig_fn);
969                 }
970                 /* if buf != NULL then fn is already free and pointing to it */
971                 if (!buf)
972                         free(fn);
973         }
974
975         ast_mutex_unlock(&formatlock);
976         if (!fs)
977                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
978
979         return fs;
980 }
981
982 int ast_waitstream(struct ast_channel *c, const char *breakon)
983 {
984         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
985         int res;
986         struct ast_frame *fr;
987         if (!breakon) breakon = "";
988         while(c->stream) {
989                 res = ast_sched_wait(c->sched);
990                 if ((res < 0) && !c->timingfunc) {
991                         ast_stopstream(c);
992                         break;
993                 }
994                 if (res < 0)
995                         res = 1000;
996                 res = ast_waitfor(c, res);
997                 if (res < 0) {
998                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
999                         return res;
1000                 } else if (res > 0) {
1001                         fr = ast_read(c);
1002                         if (!fr) {
1003 #if 0
1004                                 ast_log(LOG_DEBUG, "Got hung up\n");
1005 #endif
1006                                 return -1;
1007                         }
1008                         
1009                         switch(fr->frametype) {
1010                         case AST_FRAME_DTMF:
1011                                 res = fr->subclass;
1012                                 if (strchr(breakon, res)) {
1013                                         ast_frfree(fr);
1014                                         return res;
1015                                 }
1016                                 break;
1017                         case AST_FRAME_CONTROL:
1018                                 switch(fr->subclass) {
1019                                 case AST_CONTROL_HANGUP:
1020                                         ast_frfree(fr);
1021                                         return -1;
1022                                 case AST_CONTROL_RINGING:
1023                                 case AST_CONTROL_ANSWER:
1024                                 case AST_CONTROL_VIDUPDATE:
1025                                         /* Unimportant */
1026                                         break;
1027                                 default:
1028                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1029                                 }
1030                         }
1031                         /* Ignore */
1032                         ast_frfree(fr);
1033                 }
1034                 ast_sched_runq(c->sched);
1035         }
1036         return (c->_softhangup ? -1 : 0);
1037 }
1038
1039 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
1040 {
1041         int res;
1042         struct ast_frame *fr;
1043
1044         if (!breakon)
1045                         breakon = "";
1046         if (!forward)
1047                         forward = "";
1048         if (!rewind)
1049                         rewind = "";
1050         
1051         while(c->stream) {
1052                 res = ast_sched_wait(c->sched);
1053                 if ((res < 0) && !c->timingfunc) {
1054                         ast_stopstream(c);
1055                         break;
1056                 }
1057                 if (res < 0)
1058                         res = 1000;
1059                 res = ast_waitfor(c, res);
1060                 if (res < 0) {
1061                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1062                         return res;
1063                 } else
1064                 if (res > 0) {
1065                         fr = ast_read(c);
1066                         if (!fr) {
1067 #if 0
1068                                 ast_log(LOG_DEBUG, "Got hung up\n");
1069 #endif
1070                                 return -1;
1071                         }
1072                         
1073                         switch(fr->frametype) {
1074                         case AST_FRAME_DTMF:
1075                                 res = fr->subclass;
1076                                 if (strchr(forward,res)) {
1077                                         ast_stream_fastforward(c->stream, ms);
1078                                 } else if (strchr(rewind,res)) {
1079                                         ast_stream_rewind(c->stream, ms);
1080                                 } else if (strchr(breakon, res)) {
1081                                         ast_frfree(fr);
1082                                         return res;
1083                                 }                                       
1084                                 break;
1085                         case AST_FRAME_CONTROL:
1086                                 switch(fr->subclass) {
1087                                 case AST_CONTROL_HANGUP:
1088                                         ast_frfree(fr);
1089                                         return -1;
1090                                 case AST_CONTROL_RINGING:
1091                                 case AST_CONTROL_ANSWER:
1092                                         /* Unimportant */
1093                                         break;
1094                                 default:
1095                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1096                                 }
1097                         }
1098                         /* Ignore */
1099                         ast_frfree(fr);
1100                 } else
1101                         ast_sched_runq(c->sched);
1102         
1103                 
1104         }
1105         return (c->_softhangup ? -1 : 0);
1106 }
1107
1108 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1109 {
1110         int res;
1111         int ms;
1112         int outfd;
1113         struct ast_frame *fr;
1114         struct ast_channel *rchan;
1115
1116         if (!breakon)
1117                 breakon = "";
1118         
1119         while(c->stream) {
1120                 ms = ast_sched_wait(c->sched);
1121                 if ((ms < 0) && !c->timingfunc) {
1122                         ast_stopstream(c);
1123                         break;
1124                 }
1125                 if (ms < 0)
1126                         ms = 1000;
1127                 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1128                 if (!rchan && (outfd < 0) && (ms)) {
1129                         /* Continue */
1130                         if (errno == EINTR)
1131                                 continue;
1132                         ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1133                         return -1;
1134                 } else if (outfd > -1) {
1135                         /* The FD we were watching has something waiting */
1136                         return 1;
1137                 } else if (rchan) {
1138                         fr = ast_read(c);
1139                         if (!fr) {
1140 #if 0
1141                                 ast_log(LOG_DEBUG, "Got hung up\n");
1142 #endif
1143                                 return -1;
1144                         }
1145                         
1146                         switch(fr->frametype) {
1147                         case AST_FRAME_DTMF:
1148                                 res = fr->subclass;
1149                                 if (strchr(breakon, res)) {
1150                                         ast_frfree(fr);
1151                                         return res;
1152                                 }
1153                                 break;
1154                         case AST_FRAME_CONTROL:
1155                                 switch(fr->subclass) {
1156                                 case AST_CONTROL_HANGUP:
1157                                         ast_frfree(fr);
1158                                         return -1;
1159                                 case AST_CONTROL_RINGING:
1160                                 case AST_CONTROL_ANSWER:
1161                                         /* Unimportant */
1162                                         break;
1163                                 default:
1164                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1165                                 }
1166                         case AST_FRAME_VOICE:
1167                                 /* Write audio if appropriate */
1168                                 if (audiofd > -1)
1169                                         write(audiofd, fr->data, fr->datalen);
1170                         }
1171                         /* Ignore */
1172                         ast_frfree(fr);
1173                 }
1174                 ast_sched_runq(c->sched);
1175         }
1176         return (c->_softhangup ? -1 : 0);
1177 }
1178
1179 int ast_waitstream_exten(struct ast_channel *c, const char *context)
1180 {
1181         /* Waitstream, with return in the case of a valid 1 digit extension */
1182         /* in the current or specified context being pressed */
1183         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
1184         int res;
1185         struct ast_frame *fr;
1186         char exten[AST_MAX_EXTENSION];
1187
1188         if (!context) context = c->context;
1189         while(c->stream) {
1190                 res = ast_sched_wait(c->sched);
1191                 if ((res < 0) && !c->timingfunc) {
1192                         ast_stopstream(c);
1193                         break;
1194                 }
1195                 if (res < 0)
1196                         res = 1000;
1197                 res = ast_waitfor(c, res);
1198                 if (res < 0) {
1199                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1200                         return res;
1201                 } else if (res > 0) {
1202                         fr = ast_read(c);
1203                         if (!fr) {
1204 #if 0
1205                                 ast_log(LOG_DEBUG, "Got hung up\n");
1206 #endif
1207                                 return -1;
1208                         }
1209                         
1210                         switch(fr->frametype) {
1211                         case AST_FRAME_DTMF:
1212                                 res = fr->subclass;
1213                                 snprintf(exten, sizeof(exten), "%c", res);
1214                                 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
1215                                         ast_frfree(fr);
1216                                         return res;
1217                                 }
1218                                 break;
1219                         case AST_FRAME_CONTROL:
1220                                 switch(fr->subclass) {
1221                                 case AST_CONTROL_HANGUP:
1222                                         ast_frfree(fr);
1223                                         return -1;
1224                                 case AST_CONTROL_RINGING:
1225                                 case AST_CONTROL_ANSWER:
1226                                         /* Unimportant */
1227                                         break;
1228                                 default:
1229                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1230                                 }
1231                         }
1232                         /* Ignore */
1233                         ast_frfree(fr);
1234                 }
1235                 ast_sched_runq(c->sched);
1236         }
1237         return (c->_softhangup ? -1 : 0);
1238 }
1239
1240 static int show_file_formats(int fd, int argc, char *argv[])
1241 {
1242 #define FORMAT "%-10s %-10s %-20s\n"
1243 #define FORMAT2 "%-10s %-10s %-20s\n"
1244         struct ast_format *f;
1245         int count_fmt = 0;
1246
1247         if (argc != 3)
1248                 return RESULT_SHOWUSAGE;
1249         ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1250                 
1251         if (ast_mutex_lock(&formatlock)) {
1252                 ast_log(LOG_WARNING, "Unable to lock format list\n");
1253                 return -1;
1254         }
1255
1256         f = formats;
1257         while(f) {
1258                 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1259                 f = f->next;
1260                 count_fmt++;
1261         };
1262         ast_mutex_unlock(&formatlock);
1263         ast_cli(fd, "%d file formats registered.\n", count_fmt);
1264         return RESULT_SUCCESS;
1265 #undef FORMAT
1266 #undef FORMAT2
1267         
1268 }
1269
1270 struct ast_cli_entry show_file =
1271 {
1272         { "show", "file", "formats" },
1273         show_file_formats,
1274         "Displays file formats",
1275         "Usage: show file formats\n"
1276         "       displays currently registered file formats (if any)\n"
1277 };
1278
1279 int ast_file_init(void)
1280 {
1281         ast_cli_register(&show_file);
1282         return 0;
1283 }