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