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