aeabc77aa543177aa8df287ee09991869314e271
[asterisk/asterisk.git] / file.c
1 /*m
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 <asterisk/frame.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/sched.h>
19 #include <asterisk/options.h>
20 #include <asterisk/translate.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include "asterisk.h"
31 #include "astconf.h"
32
33 struct ast_format {
34         /* Name of format */
35         char name[80];
36         /* Extensions (separated by | if more than one) 
37            this format can read.  First is assumed for writing (e.g. .mp3) */
38         char exts[80];
39         /* Format of frames it uses/provides (one only) */
40         int format;
41         /* Open an input stream, and start playback */
42         struct ast_filestream * (*open)(int fd);
43         /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
44         struct ast_filestream * (*rewrite)(int fd, char *comment);
45         /* Apply a reading filestream to a channel */
46         int (*apply)(struct ast_channel *, struct ast_filestream *);
47         /* play filestream on a channel */
48         int (*play)(struct ast_filestream *);
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) */
58         struct ast_frame * (*read)(struct ast_filestream *);
59         /* Close file, and destroy filestream structure */
60         void (*close)(struct ast_filestream *);
61         /* Retrieve file comment */
62         char * (*getcomment)(struct ast_filestream *);
63         /* Link */
64         struct ast_format *next;
65 };
66
67 struct ast_filestream {
68         /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
69         struct ast_format *fmt;
70         /* Transparently translate from another format -- just once */
71         struct ast_trans_pvt *trans;
72         struct ast_tranlator_pvt *tr;
73 };
74
75 static pthread_mutex_t formatlock = AST_MUTEX_INITIALIZER;
76
77 static struct ast_format *formats = NULL;
78
79 int ast_format_register(char *name, char *exts, int format,
80                                                 struct ast_filestream * (*open)(int fd),
81                                                 struct ast_filestream * (*rewrite)(int fd, char *comment),
82                                                 int (*apply)(struct ast_channel *, struct ast_filestream *),
83                                                 int (*play)(struct ast_filestream *),
84                                                 int (*write)(struct ast_filestream *, struct ast_frame *),
85                                                 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
86                                                 int (*trunc)(struct ast_filestream *),
87                                                 long (*tell)(struct ast_filestream *),
88                                                 struct ast_frame * (*read)(struct ast_filestream *),
89                                                 void (*close)(struct ast_filestream *),
90                                                 char * (*getcomment)(struct ast_filestream *))
91 {
92         struct ast_format *tmp;
93         if (ast_pthread_mutex_lock(&formatlock)) {
94                 ast_log(LOG_WARNING, "Unable to lock format list\n");
95                 return -1;
96         }
97         tmp = formats;
98         while(tmp) {
99                 if (!strcasecmp(name, tmp->name)) {
100                         ast_pthread_mutex_unlock(&formatlock);
101                         ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
102                         return -1;
103                 }
104                 tmp = tmp->next;
105         }
106         tmp = malloc(sizeof(struct ast_format));
107         if (!tmp) {
108                 ast_log(LOG_WARNING, "Out of memory\n");
109                 ast_pthread_mutex_unlock(&formatlock);
110                 return -1;
111         }
112         strncpy(tmp->name, name, sizeof(tmp->name)-1);
113         strncpy(tmp->exts, exts, sizeof(tmp->exts)-1);
114         tmp->open = open;
115         tmp->rewrite = rewrite;
116         tmp->apply = apply;
117         tmp->play = play;
118         tmp->read = read;
119         tmp->write = write;
120         tmp->seek = seek;
121         tmp->trunc = trunc;
122         tmp->tell = tell;
123         tmp->close = close;
124         tmp->format = format;
125         tmp->getcomment = getcomment;
126         tmp->next = formats;
127         formats = tmp;
128         ast_pthread_mutex_unlock(&formatlock);
129         if (option_verbose > 1)
130                 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
131         return 0;
132 }
133
134 int ast_format_unregister(char *name)
135 {
136         struct ast_format *tmp, *tmpl = NULL;
137         if (ast_pthread_mutex_lock(&formatlock)) {
138                 ast_log(LOG_WARNING, "Unable to lock format list\n");
139                 return -1;
140         }
141         tmp = formats;
142         while(tmp) {
143                 if (!strcasecmp(name, tmp->name)) {
144                         if (tmpl) 
145                                 tmpl->next = tmp->next;
146                         else
147                                 formats = tmp->next;
148                         free(tmp);
149                         ast_pthread_mutex_unlock(&formatlock);
150                         if (option_verbose > 1)
151                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
152                         return 0;
153                 }
154                 tmp = tmp->next;
155         }
156         ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
157         return -1;
158 }
159
160 int ast_stopstream(struct ast_channel *tmp)
161 {
162         /* Stop a running stream if there is one */
163         if (!tmp->stream) 
164                 return 0;
165         tmp->stream->fmt->close(tmp->stream);
166         if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
167                 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
168         return 0;
169 }
170
171 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
172 {
173         struct ast_frame *trf;
174         int res = -1;
175         if (f->frametype != AST_FRAME_VOICE) {
176                 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
177                 return -1;
178         }
179         if ((fs->fmt->format & f->subclass) == f->subclass) {
180                 res =  fs->fmt->write(fs, f);
181                 if (res < 0) 
182                         ast_log(LOG_WARNING, "Natural write failed\n");
183                 if (res > 0)
184                         ast_log(LOG_WARNING, "Huh??\n");
185                 return res;
186         } else {
187                 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
188                        the one we've setup a translator for, we do the "wrong thing" XXX */
189                 if (!fs->trans) 
190                         fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
191                 if (!fs->trans)
192                         ast_log(LOG_WARNING, "Unable to translate to format %s, source format %d\n", fs->fmt->name, f->subclass);
193                 else {
194                         res = 0;
195                         /* Get the translated frame but don't consume the original in case they're using it on another stream */
196                         trf = ast_translate(fs->trans, f, 0);
197                         if (trf) {
198                                 res = fs->fmt->write(fs, trf);
199                                 if (res) 
200                                         ast_log(LOG_WARNING, "Translated frame write failed\n");
201                         } else
202                                 res = 0;
203                 }
204                 return res;
205         }
206 }
207
208 static int copy(char *infile, char *outfile)
209 {
210         int ifd;
211         int ofd;
212         int res;
213         int len;
214         char buf[4096];
215         if ((ifd = open(infile, O_RDONLY)) < 0) {
216                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
217                 return -1;
218         }
219         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
220                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
221                 close(ifd);
222                 return -1;
223         }
224         do {
225                 len = read(ifd, buf, sizeof(buf));
226                 if (len < 0) {
227                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
228                         close(ifd);
229                         close(ofd);
230                         unlink(outfile);
231                 }
232                 if (len) {
233                         res = write(ofd, buf, len);
234                         if (res != len) {
235                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
236                                 close(ifd);
237                                 close(ofd);
238                                 unlink(outfile);
239                         }
240                 }
241         } while(len);
242         close(ifd);
243         close(ofd);
244         return 0;
245 }
246
247 static char *build_filename(char *filename, char *ext)
248 {
249         char *fn;
250         char tmp[AST_CONFIG_MAX_PATH];
251         snprintf((char *)tmp,sizeof(tmp)-1,"%s/%s",(char *)ast_config_AST_VAR_DIR,"sounds");
252         fn = malloc(strlen(tmp) + strlen(filename) + strlen(ext) + 10);
253         if (fn) {
254                 if (filename[0] == '/') 
255                         sprintf(fn, "%s.%s", filename, ext);
256                 else
257                         sprintf(fn, "%s/%s.%s", (char *)tmp, filename, ext);
258         }
259         return fn;
260         
261 }
262
263 #define ACTION_EXISTS 1
264 #define ACTION_DELETE 2
265 #define ACTION_RENAME 3
266 #define ACTION_OPEN   4
267 #define ACTION_COPY   5
268
269 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
270 {
271         struct stat st;
272         struct ast_format *f;
273         struct ast_filestream *s;
274         int res=0, ret = 0;
275         char *ext=NULL, *exts, *fn, *nfn;
276         struct ast_channel *chan = (struct ast_channel *)filename2;
277         
278         /* Start with negative response */
279         if (action == ACTION_EXISTS)
280                 res = 0;
281         else
282                 res = -1;
283         if (action == ACTION_OPEN)
284                 ret = -1;
285         /* Check for a specific format */
286         if (ast_pthread_mutex_lock(&formatlock)) {
287                 ast_log(LOG_WARNING, "Unable to lock format list\n");
288                 if (action == ACTION_EXISTS)
289                         return 0;
290                 else
291                         return -1;
292         }
293         f = formats;
294         while(f) {
295                 if (!fmt || !strcasecmp(f->name, fmt)) {
296                         char *stringp=NULL;
297                         exts = strdup(f->exts);
298                         /* Try each kind of extension */
299                         stringp=exts;
300                         ext = strsep(&stringp, "|");
301                         do {
302                                 fn = build_filename(filename, ext);
303                                 if (fn) {
304                                         res = stat(fn, &st);
305                                         if (!res) {
306                                                 switch(action) {
307                                                 case ACTION_EXISTS:
308                                                         ret |= f->format;
309                                                         break;
310                                                 case ACTION_DELETE:
311                                                         res = unlink(fn);
312                                                         if (res)
313                                                                 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
314                                                         break;
315                                                 case ACTION_RENAME:
316                                                         nfn = build_filename(filename2, ext);
317                                                         if (nfn) {
318                                                                 res = rename(fn, nfn);
319                                                                 if (res)
320                                                                         ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
321                                                                 free(nfn);
322                                                         } else
323                                                                 ast_log(LOG_WARNING, "Out of memory\n");
324                                                         break;
325                                                 case ACTION_COPY:
326                                                         nfn = build_filename(filename2, ext);
327                                                         if (nfn) {
328                                                                 res = copy(fn, nfn);
329                                                                 if (res)
330                                                                         ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
331                                                                 free(nfn);
332                                                         } else
333                                                                 ast_log(LOG_WARNING, "Out of memory\n");
334                                                         break;
335                                                 case ACTION_OPEN:
336                                                         if ((ret < 0) && ((chan->writeformat & f->format))) {
337                                                                 ret = open(fn, O_RDONLY);
338                                                                 if (ret >= 0) {
339                                                                         s = f->open(ret);
340                                                                         if (s) {
341                                                                                 s->fmt = f;
342                                                                                 s->trans = NULL;
343                                                                                 chan->stream = s;
344                                                                         } else {
345                                                                                 close(ret);
346                                                                                 ast_log(LOG_WARNING, "Unable to open fd on %s\n", filename);
347                                                                         }
348                                                                 } else
349                                                                         ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
350                                                         }
351                                                         break;
352                                                 default:
353                                                         ast_log(LOG_WARNING, "Unknown helper %d\n", action);
354                                                 }
355                                                 /* Conveniently this logic is the same for all */
356                                                 if (res)
357                                                         break;
358                                         }
359                                         free(fn);
360                                 }
361                                 ext = strsep(&stringp, "|");
362                         } while(ext);
363                         free(exts);
364                 }
365                 f = f->next;
366         }
367         ast_pthread_mutex_unlock(&formatlock);
368         if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
369                 res = ret ? ret : -1;
370         return res;
371 }
372
373 struct ast_filestream *ast_openstream(struct ast_channel *chan, char *filename, char *preflang)
374 {
375         /* This is a fairly complex routine.  Essentially we should do 
376            the following:
377            
378            1) Find which file handlers produce our type of format.
379            2) Look for a filename which it can handle.
380            3) If we find one, then great.  
381            4) If not, see what files are there
382            5) See what we can actually support
383            6) Choose the one with the least costly translator path and
384                set it up.
385                    
386         */
387         int fd = -1;
388         int fmts = -1;
389         char filename2[256];
390         char lang2[MAX_LANGUAGE];
391         int res;
392         ast_stopstream(chan);
393         /* do this first, otherwise we detect the wrong writeformat */
394         if (chan->generator)
395                 ast_deactivate_generator(chan);
396         if (preflang && strlen(preflang)) {
397                 snprintf(filename2, sizeof(filename2), "%s-%s", filename, preflang);
398                 fmts = ast_fileexists(filename2, NULL, NULL);
399                 if (fmts < 1) {
400                         strncpy(lang2, preflang, sizeof(lang2)-1);
401                         snprintf(filename2, sizeof(filename2), "%s-%s", filename, lang2);
402                         fmts = ast_fileexists(filename2, NULL, NULL);
403                 }
404         }
405         if (fmts < 1) {
406                 strncpy(filename2, filename, sizeof(filename2)-1);
407                 fmts = ast_fileexists(filename2, NULL, NULL);
408         }
409         if (fmts < 1) {
410                 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
411                 return NULL;
412         }
413         chan->oldwriteformat = chan->writeformat;
414         /* Set the channel to a format we can work with */
415         res = ast_set_write_format(chan, fmts);
416         
417         fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
418         if(fd >= 0)
419                 return chan->stream;
420         return NULL;
421 }
422
423 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
424 {
425         if(chan->stream->fmt->apply(chan,s)){
426                 chan->stream->fmt->close(s);
427                 chan->stream = NULL;
428                 ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", chan->name);
429                 return -1;
430         }
431         return 0;
432 }
433
434 int ast_playstream(struct ast_filestream *s)
435 {
436         if(s->fmt->play(s)){
437                 ast_closestream(s);
438                 ast_log(LOG_WARNING, "Unable to start playing stream\n");
439                 return -1;
440         }
441         return 0;
442 }
443
444 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
445 {
446         return fs->fmt->seek(fs, sample_offset, whence);
447 }
448
449 int ast_truncstream(struct ast_filestream *fs)
450 {
451         return fs->fmt->trunc(fs);
452 }
453
454 long ast_tellstream(struct ast_filestream *fs)
455 {
456         return fs->fmt->tell(fs);
457 }
458
459 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
460 {
461         /* I think this is right, 8000 samples per second, 1000 ms a second so 8
462          * samples per ms  */
463         long samples = ms * 8;
464         return ast_seekstream(fs, samples, SEEK_CUR);
465 }
466
467 int ast_stream_rewind(struct ast_filestream *fs, long ms)
468 {
469         long samples = ms * 8;
470         samples = samples * -1;
471         return ast_seekstream(fs, samples, SEEK_CUR);
472 }
473
474 int ast_closestream(struct ast_filestream *f)
475 {
476         /* Stop a running stream if there is one */
477         f->fmt->close(f);
478         return 0;
479 }
480
481
482 int ast_fileexists(char *filename, char *fmt, char *preflang)
483 {
484         char filename2[256];
485         char tmp[256];
486         char *postfix;
487         char *prefix;
488         char *c;
489         char lang2[MAX_LANGUAGE];
490         int res = -1;
491         if (preflang && strlen(preflang)) {
492                 /* Insert the language between the last two parts of the path */
493                 strncpy(tmp, filename, sizeof(tmp) - 1);
494                 c = strrchr(tmp, '/');
495                 if (c) {
496                         *c = '\0';
497                         postfix = c+1;
498                         prefix = tmp;
499                 } else {
500                         postfix = tmp;
501                         prefix="";
502                 }
503                 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
504                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
505                 if (res < 1) {
506                         char *stringp=NULL;
507                         strncpy(lang2, preflang, sizeof(lang2)-1);
508                         stringp=lang2;
509                         strsep(&stringp, "_");
510                         if (strcmp(lang2, preflang)) {
511                                 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
512                                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
513                         }
514                 }
515         }
516         if (res < 1) {
517                 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
518         }
519         return res;
520 }
521
522 int ast_filedelete(char *filename, char *fmt)
523 {
524         return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
525 }
526
527 int ast_filerename(char *filename, char *filename2, char *fmt)
528 {
529         return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
530 }
531
532 int ast_filecopy(char *filename, char *filename2, char *fmt)
533 {
534         return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
535 }
536
537 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
538 {
539         struct ast_filestream *fs;
540
541         fs = ast_openstream(chan, filename, preflang);
542         if(fs){
543                 if(ast_applystream(chan, fs))
544                         return -1;
545                 if(ast_playstream(fs))
546                         return -1;
547 #if 1
548                 if (option_verbose > 2)
549                         ast_verbose(VERBOSE_PREFIX_3 "Playing '%s'\n", filename);
550 #endif
551                 return 0;
552         }
553         ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->nativeformats, strerror(errno));
554         return -1;
555 }
556
557
558 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
559 {
560         int fd,myflags;
561         struct ast_format *f;
562         struct ast_filestream *fs=NULL;
563         char *fn;
564         char *ext;
565         if (ast_pthread_mutex_lock(&formatlock)) {
566                 ast_log(LOG_WARNING, "Unable to lock format list\n");
567                 return NULL;
568         }
569         myflags = 0;
570         /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
571         //if (!(flags & O_APPEND)) myflags = O_TRUNC;
572         f = formats;
573         while(f) {
574                 if (!strcasecmp(f->name, type)) {
575                         char *stringp=NULL;
576                         /* XXX Implement check XXX */
577                         ext = strdup(f->exts);
578                         stringp=ext;
579                         ext = strsep(&stringp, "|");
580                         fn = build_filename(filename, ext);
581                         fd = open(fn, flags | myflags | O_WRONLY | O_CREAT, mode);
582                         if (fd >= 0) {
583                                 errno = 0;
584                                 if ((fs = f->rewrite(fd, comment))) {
585                                         fs->trans = NULL;
586                                         fs->fmt = f;
587                                 } else {
588                                         ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
589                                         close(fd);
590                                         unlink(fn);
591                                 }
592                         } else if (errno != EEXIST)
593                                 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
594                         free(fn);
595                         free(ext);
596                         break;
597                 }
598                 f = f->next;
599         }
600         ast_pthread_mutex_unlock(&formatlock);
601         if (!f) 
602                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
603         return fs;
604 }
605
606 char ast_waitstream(struct ast_channel *c, char *breakon)
607 {
608         int res;
609         struct ast_frame *fr;
610         while(c->stream) {
611                 res = ast_sched_wait(c->sched);
612                 if (res < 0) {
613                         ast_closestream(c->stream);
614                         break;
615                 }
616                 res = ast_waitfor(c, res);
617                 if (res < 0) {
618                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
619                         return res;
620                 } else
621                 if (res > 0) {
622                         fr = ast_read(c);
623                         if (!fr) {
624 #if 0
625                                 ast_log(LOG_DEBUG, "Got hung up\n");
626 #endif
627                                 return -1;
628                         }
629                         
630                         switch(fr->frametype) {
631                         case AST_FRAME_DTMF:
632                                 res = fr->subclass;
633                                 if (strchr(breakon, res)) {
634                                         ast_frfree(fr);
635                                         return res;
636                                 }
637                                 break;
638                         case AST_FRAME_CONTROL:
639                                 switch(fr->subclass) {
640                                 case AST_CONTROL_HANGUP:
641                                         ast_frfree(fr);
642                                         return -1;
643                                 case AST_CONTROL_RINGING:
644                                 case AST_CONTROL_ANSWER:
645                                         /* Unimportant */
646                                         break;
647                                 default:
648                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
649                                 }
650                         }
651                         /* Ignore */
652                         ast_frfree(fr);
653                 } else
654                         ast_sched_runq(c->sched);
655         
656                 
657         }
658         return (c->_softhangup ? -1 : 0);
659 }
660