fix bug added to my code so I don
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Routines implementing music on hold
5  * 
6  * Copyright (C) 1999-2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <../astconf.h>
20 #include <asterisk/options.h>
21 #include <asterisk/module.h>
22 #include <asterisk/translate.h>
23 #include <asterisk/say.h>
24 #include <asterisk/channel_pvt.h>
25 #include <asterisk/musiconhold.h>
26 #include <asterisk/config.h>
27 #include <asterisk/utils.h>
28 #include <stdlib.h>
29 #include <asterisk/cli.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/time.h>
37 #include <sys/signal.h>
38 #include <netinet/in.h>
39 #include <sys/stat.h>
40 #include <dirent.h>
41 #ifdef ZAPATA_MOH
42 #ifdef __linux__
43 #include <linux/zaptel.h>
44 #else
45 #include <zaptel.h>
46 #endif /* __linux__ */
47 #endif
48 #include <unistd.h>
49 #include <sys/ioctl.h>
50 #define MAX_MOHFILES 512
51 #define MAX_MOHFILE_LEN 128
52
53 static char *app0 = "MusicOnHold";
54 static char *app1 = "WaitMusicOnHold";
55 static char *app2 = "SetMusicOnHold";
56
57 static char *synopsis0 = "Play Music On Hold indefinitely";
58 static char *synopsis1 = "Wait, playing Music On Hold";
59 static char *synopsis2 = "Set default Music On Hold class";
60
61 static char *descrip0 = "MusicOnHold(class): "
62 "Plays hold music specified by class.  If omitted, the default\n"
63 "music source for the channel will be used. Set the default \n"
64 "class with the SetMusicOnHold() application.\n"
65 "Returns -1 on hangup.\n"
66 "Never returns otherwise.\n";
67
68 static char *descrip1 = "WaitMusicOnHold(delay): "
69 "Plays hold music specified number of seconds.  Returns 0 when\n"
70 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
71 "still occur with no sound.\n";
72
73 static char *descrip2 = "SetMusicOnHold(class): "
74 "Sets the default class for music on hold for a given channel.  When\n"
75 "music on hold is activated, this class will be used to select which\n"
76 "music is played.\n";
77
78 static int respawn_time = 20;
79
80 struct moh_files_state {
81         struct mohclass *class;
82         struct ast_filestream *stream;
83         int origwfmt;
84         int samples;
85         int sample_queue;
86         unsigned char pos;
87         unsigned char save_pos;
88 };
89
90 struct mohclass {
91         char class[80];
92         char dir[256];
93         char miscargs[256];
94         char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
95         int total_files;
96         int destroyme;
97         int pid;                /* PID of mpg123 */
98         int quiet;
99         int single;
100         int custom;
101         int randomize;
102         time_t start;
103         pthread_t thread;
104         struct mohdata *members;
105         /* Source of audio */
106         int srcfd;
107         /* FD for timing source */
108         int pseudofd;
109         struct mohclass *next;
110 };
111
112 struct mohdata {
113         int pipe[2];
114         int origwfmt;
115         struct mohclass *parent;
116         struct mohdata *next;
117 };
118
119 static struct mohclass *mohclasses;
120
121 AST_MUTEX_DEFINE_STATIC(moh_lock);
122
123 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
124 #define MPG_123 "/usr/bin/mpg123"
125 #define MAX_MP3S 256
126
127 static void moh_files_release(struct ast_channel *chan, void *data)
128 {
129         struct moh_files_state *state = chan->music_state;
130
131         if (chan && state) {
132                 if (option_verbose > 2)
133                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
134
135                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
136                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
137                 }
138                 state->save_pos = state->pos + 1;
139         }
140 }
141
142
143 static int ast_moh_files_next(struct ast_channel *chan) {
144         struct moh_files_state *state = chan->music_state;
145
146         if(state->save_pos) {
147                 state->pos = state->save_pos - 1;
148                 state->save_pos = 0;
149         } else {
150                 state->samples = 0;
151                 if (chan->stream) {
152                         ast_closestream(chan->stream);
153                         chan->stream = NULL;
154                         state->pos++;
155                 }
156
157                 if (state->class->randomize) {
158                         srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files);
159                         state->pos = rand();
160                 }
161         }
162
163         state->pos = state->pos % state->class->total_files;
164         
165         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
166                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
167                 return -1;
168         }
169         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
170                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
171                 state->pos++;
172                 return -1;
173         }
174
175         if (option_verbose > 2)
176                 ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
177
178
179         if (state->samples)
180                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
181
182         return state->pos;
183 }
184
185
186 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) {
187         struct ast_frame *f = NULL;
188         
189         if (!chan->stream || !(f = ast_readframe(chan->stream))) {
190                 if (ast_moh_files_next(chan) > -1)
191                         f = ast_readframe(chan->stream);
192         }
193
194         return f;
195 }
196
197 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
198 {
199         struct moh_files_state *state = chan->music_state;
200         struct ast_frame *f = NULL;
201         int res = 0;
202         state->sample_queue += samples;
203
204         while(state->sample_queue > 0) {
205                 if ((f = moh_files_readframe(chan))) {
206                         state->samples += f->samples;
207                         res = ast_write(chan, f);
208                         ast_frfree(f);
209                         if(res < 0) {
210                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
211                                 return -1;
212                         }
213                         state->sample_queue -= f->samples;
214                 } else
215                         return -1;      
216         }
217         return res;
218 }
219
220
221 static void *moh_files_alloc(struct ast_channel *chan, void *params)
222 {
223         struct moh_files_state *state;
224         struct mohclass *class = params;
225         int allocated = 0;
226
227         if ((!chan->music_state) && ((state = malloc(sizeof(struct moh_files_state))))) {
228                 chan->music_state = state;
229                 allocated = 1;
230         } else 
231                 state = chan->music_state;
232
233
234         if(state) {
235                 if (allocated || state->class != class) {
236                         /* initialize */
237                         memset(state, 0, sizeof(struct moh_files_state));
238                         state->class = class;
239                 }
240
241                 state->origwfmt = chan->writeformat;
242
243                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
244                         ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
245                         free(chan->music_state);
246                         chan->music_state = NULL;
247                 } else {
248                         if (option_verbose > 2)
249                                 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
250                 }
251
252
253         }
254         
255         return chan->music_state;
256 }
257
258 static struct ast_generator moh_file_stream = 
259 {
260         alloc: moh_files_alloc,
261         release: moh_files_release,
262         generate: moh_files_generator,
263 };
264
265 static int spawn_mp3(struct mohclass *class)
266 {
267         int fds[2];
268         int files=0;
269         char fns[MAX_MP3S][80];
270         char *argv[MAX_MP3S + 50];
271         char xargs[256];
272         char *argptr;
273         int argc = 0;
274         DIR *dir;
275         struct dirent *de;
276
277         
278         dir = opendir(class->dir);
279         if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
280                 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
281                 return -1;
282         }
283
284         if (!class->custom) {
285                 argv[argc++] = "mpg123";
286                 argv[argc++] = "-q";
287                 argv[argc++] = "-s";
288                 argv[argc++] = "--mono";
289                 argv[argc++] = "-r";
290                 argv[argc++] = "8000";
291                 
292                 if (!class->single) {
293                         argv[argc++] = "-b";
294                         argv[argc++] = "2048";
295                 }
296                 
297                 argv[argc++] = "-f";
298                 
299                 if (class->quiet)
300                         argv[argc++] = "4096";
301                 else
302                         argv[argc++] = "8192";
303                 
304                 /* Look for extra arguments and add them to the list */
305                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
306                 argptr = xargs;
307                 while(argptr && !ast_strlen_zero(argptr)) {
308                         argv[argc++] = argptr;
309                         argptr = strchr(argptr, ',');
310                         if (argptr) {
311                                 *argptr = '\0';
312                                 argptr++;
313                         }
314                 }
315         } else  {
316                 /* Format arguments for argv vector */
317                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
318                 argptr = xargs;
319                 while(argptr && !ast_strlen_zero(argptr)) {
320                         argv[argc++] = argptr;
321                         argptr = strchr(argptr, ' ');
322                         if (argptr) {
323                                 *argptr = '\0';
324                                 argptr++;
325                         }
326                 }
327         }
328
329         files = 0;
330         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
331                 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
332                 argv[argc++] = fns[files];
333                 files++;
334         } else {
335                 while((de = readdir(dir)) && (files < MAX_MP3S)) {
336                         if ((strlen(de->d_name) > 3) && 
337                                 ((class->custom && 
338                                   (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
339                                    !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln")))
340                                  || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
341                                 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
342                                 argv[argc++] = fns[files];
343                                 files++;
344                         }
345                 }
346         }
347         argv[argc] = NULL;
348         closedir(dir);
349         
350         if (pipe(fds)) {        
351                 ast_log(LOG_WARNING, "Pipe failed\n");
352                 return -1;
353         }
354 #if 0
355         printf("%d files total, %d args total\n", files, argc);
356         {
357                 int x;
358                 for (x=0;argv[x];x++)
359                         printf("arg%d: %s\n", x, argv[x]);
360         }
361 #endif  
362         if (!files) {
363                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
364                 close(fds[0]);
365                 close(fds[1]);
366                 return -1;
367         }
368         if (time(NULL) - class->start < respawn_time) {
369                 sleep(respawn_time - (time(NULL) - class->start));
370         }
371         time(&class->start);
372         class->pid = fork();
373         if (class->pid < 0) {
374                 close(fds[0]);
375                 close(fds[1]);
376                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
377                 return -1;
378         }
379         if (!class->pid) {
380                 int x;
381                 close(fds[0]);
382                 /* Stdout goes to pipe */
383                 dup2(fds[1], STDOUT_FILENO);
384                 /* Close unused file descriptors */
385                 for (x=3;x<8192;x++) {
386                         if (-1 != fcntl(x, F_GETFL)) {
387                                 close(x);
388                         }
389                 }
390         /* Child */
391                 chdir(class->dir);
392                 if(class->custom) {
393                         execv(argv[0], argv);
394         } else {
395             /* Default install is /usr/local/bin */
396             execv(LOCAL_MPG_123, argv);
397             /* Many places have it in /usr/bin */
398             execv(MPG_123, argv);
399             /* Check PATH as a last-ditch effort */
400             execvp("mpg123", argv);
401         }
402                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
403                 close(fds[1]);
404                 exit(1);
405         } else {
406                 /* Parent */
407                 close(fds[1]);
408         }
409         return fds[0];
410 }
411
412 static void *monmp3thread(void *data)
413 {
414 #define MOH_MS_INTERVAL         100
415
416         struct mohclass *class = data;
417         struct mohdata *moh;
418         char buf[8192];
419         short sbuf[8192];
420         int res, res2;
421         struct timeval tv;
422         struct timeval tv_tmp;
423         long error_sec, error_usec;
424         long delay;
425
426         tv_tmp.tv_sec = 0;
427         tv_tmp.tv_usec = 0;
428         tv.tv_sec = 0;
429         tv.tv_usec = 0;
430         error_sec = 0;
431         error_usec = 0;
432         for(;/* ever */;) {
433                 /* Spawn mp3 player if it's not there */
434                 if (class->srcfd < 0) {
435                         if ((class->srcfd = spawn_mp3(class)) < 0) {
436                                 ast_log(LOG_WARNING, "unable to spawn mp3player\n");
437                                 /* Try again later */
438                                 sleep(500);
439                         }
440                 }
441                 if (class->pseudofd > -1) {
442                         /* Pause some amount of time */
443                         res = read(class->pseudofd, buf, sizeof(buf));
444                 } else {
445                         /* Reliable sleep */
446                         if (gettimeofday(&tv_tmp, NULL) < 0) {
447                                 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
448                                 return NULL;
449                         }
450                         if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
451                                 if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
452                                         tv_tmp.tv_usec += 1000000;
453                                         tv_tmp.tv_sec -= 1;
454                                 }
455                                 error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
456                                 error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
457                         } else {
458                                 error_sec = 0;
459                                 error_usec = 0;
460                         }
461                         if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
462                                 tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
463                                 tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
464                                 delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
465                                                         ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
466                         } else {
467                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
468                                 tv.tv_sec = tv_tmp.tv_sec;
469                                 tv.tv_usec = tv_tmp.tv_usec;
470                                 delay = 0;
471                         }
472                         if (tv.tv_usec > 1000000) {
473                                 tv.tv_sec++;
474                                 tv.tv_usec-= 1000000;
475                         }
476                         if (delay > 0)
477                                 usleep(delay * 1000);
478                         res = 800;              /* 800 samples */
479                 }
480                 if (!class->members)
481                         continue;
482                 /* Read mp3 audio */
483                 if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) {
484                         if (!res2) {
485                                 close(class->srcfd);
486                                 class->srcfd = -1;
487                                 if (class->pid) {
488                                         kill(class->pid, SIGKILL);
489                                         class->pid = 0;
490                                 }
491                         } else
492                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
493                         continue;
494                 }
495                 ast_mutex_lock(&moh_lock);
496                 moh = class->members;
497                 while(moh) {
498                         /* Write data */
499                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
500                                 if (option_debug)
501                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
502                         moh = moh->next;
503                 }
504                 ast_mutex_unlock(&moh_lock);
505         }
506         return NULL;
507 }
508
509 static int moh0_exec(struct ast_channel *chan, void *data)
510 {
511         if (ast_moh_start(chan, data)) {
512                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
513                 return -1;
514         }
515         while(!ast_safe_sleep(chan, 10000));
516         return -1;
517 }
518
519 static int moh1_exec(struct ast_channel *chan, void *data)
520 {
521         int res;
522         if (!data || !atoi(data)) {
523                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
524                 return -1;
525         }
526         if (ast_moh_start(chan, NULL)) {
527                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
528                 return -1;
529         }
530         res = ast_safe_sleep(chan, atoi(data) * 1000);
531         ast_moh_stop(chan);
532         return res;
533 }
534
535 static int moh2_exec(struct ast_channel *chan, void *data)
536 {
537         if (!data || ast_strlen_zero(data)) {
538                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
539                 return -1;
540         }
541         strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
542         return 0;
543 }
544
545 static struct mohclass *get_mohbyname(char *name)
546 {
547         struct mohclass *moh;
548         moh = mohclasses;
549         while(moh) {
550                 if (!strcasecmp(name, moh->class))
551                         return moh;
552                 moh = moh->next;
553         }
554         return NULL;
555 }
556
557 static struct mohdata *mohalloc(struct mohclass *cl)
558 {
559         struct mohdata *moh;
560         long flags;
561         moh = malloc(sizeof(struct mohdata));
562         if (!moh)
563                 return NULL;
564         memset(moh, 0, sizeof(struct mohdata));
565         if (pipe(moh->pipe)) {
566                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
567                 free(moh);
568                 return NULL;
569         }
570         /* Make entirely non-blocking */
571         flags = fcntl(moh->pipe[0], F_GETFL);
572         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
573         flags = fcntl(moh->pipe[1], F_GETFL);
574         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
575         moh->parent = cl;
576         moh->next = cl->members;
577         cl->members = moh;
578         return moh;
579 }
580
581 static void moh_release(struct ast_channel *chan, void *data)
582 {
583         struct mohdata *moh = data, *prev, *cur;
584         int oldwfmt;
585         ast_mutex_lock(&moh_lock);
586         /* Unlink */
587         prev = NULL;
588         cur = moh->parent->members;
589         while(cur) {
590                 if (cur == moh) {
591                         if (prev)
592                                 prev->next = cur->next;
593                         else
594                                 moh->parent->members = cur->next;
595                         break;
596                 }
597                 prev = cur;
598                 cur = cur->next;
599         }
600         ast_mutex_unlock(&moh_lock);
601         close(moh->pipe[0]);
602         close(moh->pipe[1]);
603         oldwfmt = moh->origwfmt;
604         free(moh);
605         if (chan) {
606                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
607                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
608                 if (option_verbose > 2)
609                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
610         }
611 }
612
613 static void *moh_alloc(struct ast_channel *chan, void *params)
614 {
615         struct mohdata *res;
616         struct mohclass *class;
617         class = params;
618         if (class)
619                 res = mohalloc(class);
620         else {
621                 if (strcasecmp(params, "default"))
622                         ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
623                 res = NULL;
624         }
625         if (res) {
626                 res->origwfmt = chan->writeformat;
627                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
628                         ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
629                         moh_release(NULL, res);
630                         res = NULL;
631                 }
632                 if (option_verbose > 2)
633                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
634         }
635         return res;
636 }
637
638 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
639 {
640         struct ast_frame f;
641         struct mohdata *moh = data;
642         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
643         int res;
644         if(!moh->parent->pid)
645                 return - 1;
646         len = samples * 2;
647         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
648                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), (int)len, chan->name);
649                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
650         }
651         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
652 #if 0
653         if (res != len) {
654                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
655         }
656 #endif
657         if (res > 0) {
658                 memset(&f, 0, sizeof(f));
659                 f.frametype = AST_FRAME_VOICE;
660                 f.subclass = AST_FORMAT_SLINEAR;
661                 f.mallocd = 0;
662                 f.datalen = res;
663                 f.samples = res / 2;
664                 f.data = buf + AST_FRIENDLY_OFFSET / 2;
665                 f.offset = AST_FRIENDLY_OFFSET;
666                 if (ast_write(chan, &f)< 0) {
667                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
668                         return -1;
669                 }
670         }
671         return 0;
672 }
673
674 static struct ast_generator mohgen = 
675 {
676         alloc: moh_alloc,
677         release: moh_release,
678         generate: moh_generate,
679 };
680
681 static int moh_scan_files(struct mohclass *class) {
682
683         DIR *files_DIR;
684         struct dirent *files_dirent;
685         char path[512];
686         char filepath[MAX_MOHFILE_LEN];
687         char *ext;
688         struct stat statbuf;
689         int dirnamelen;
690         int i;
691         
692         files_DIR = opendir(class->dir);
693         if (!files_DIR) {
694                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
695                 return -1;
696         }
697
698         class->total_files = 0;
699         dirnamelen = strlen(class->dir) + 2;
700         getcwd(path, 512);
701         chdir(class->dir);
702         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
703
704         while ((files_dirent = readdir(files_DIR))) {
705                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
706                         continue;
707
708                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
709
710                 if (stat(filepath, &statbuf))
711                         continue;
712
713                 if (!S_ISREG(statbuf.st_mode))
714                         continue;
715
716                 if ((ext = strrchr(filepath, '.'))) {
717                         *ext = '\0';
718                         ext++;
719                 }
720
721                 /* check to see if this file's format can be opened */
722                 if (ast_fileexists(filepath, ext, NULL) == -1)
723                         continue;
724
725                 /* if the file is present in multiple formats, ensure we only put it into the list once */
726                 for (i = 0; i < class->total_files; i++)
727                         if (!strcmp(filepath, class->filearray[i]))
728                                 break;
729
730                 if (i == class->total_files)
731                         strcpy(class->filearray[class->total_files++], filepath);
732         }
733
734         closedir(files_DIR);
735         chdir(path);
736         return class->total_files;
737 }
738
739 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
740 {
741         struct mohclass *moh;
742 #ifdef ZAPATA_MOH
743         int x;
744 #endif
745         ast_mutex_lock(&moh_lock);
746         moh = get_mohbyname(classname);
747         ast_mutex_unlock(&moh_lock);
748         if (moh) {
749                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
750                 return -1;
751         }
752         moh = malloc(sizeof(struct mohclass));
753         if (!moh)
754                 return -1;
755         memset(moh, 0, sizeof(struct mohclass));
756         time(&moh->start);
757         moh->start -= respawn_time;
758         strncpy(moh->class, classname, sizeof(moh->class) - 1);
759         if (miscargs) {
760                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
761                 if (strchr(miscargs,'r'))
762                         moh->randomize=1;
763         }
764         if (!strcasecmp(mode, "files")) {
765                 if (param)
766                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
767                 if (!moh_scan_files(moh)) {
768                         free(moh);
769                         return -1;
770                 }
771         } else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
772
773                 if (param)
774                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
775
776                 if (!strcasecmp(mode, "custom"))
777                         moh->custom = 1;
778                 else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
779                         moh->single = 1;
780                 else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
781                         moh->quiet = 1;
782                 
783                 moh->srcfd = -1;
784 #ifdef ZAPATA_MOH
785                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
786                    there a better, yet reliable way to do this? */
787                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
788                 if (moh->pseudofd < 0) {
789                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
790                 } else {
791                         x = 320;
792                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
793                 }
794 #else
795                 moh->pseudofd = -1;
796 #endif
797                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
798                         ast_log(LOG_WARNING, "Unable to create moh...\n");
799                         if (moh->pseudofd > -1)
800                                 close(moh->pseudofd);
801                         free(moh);
802                         return -1;
803                 }
804         } else {
805                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
806                 free(moh);
807                 return -1;
808         }
809         ast_mutex_lock(&moh_lock);
810         moh->next = mohclasses;
811         mohclasses = moh;
812         ast_mutex_unlock(&moh_lock);
813         return 0;
814 }
815
816 static void local_ast_moh_cleanup(struct ast_channel *chan)
817 {
818         if(chan->music_state) {
819                 free(chan->music_state);
820                 chan->music_state = NULL;
821         }
822 }
823
824 static int local_ast_moh_start(struct ast_channel *chan, char *class)
825 {
826         struct mohclass *mohclass;
827
828         if (!class || ast_strlen_zero(class))
829                 class = chan->musicclass;
830         if (!class || ast_strlen_zero(class))
831                 class = "default";
832         ast_mutex_lock(&moh_lock);
833         mohclass = get_mohbyname(class);
834         ast_mutex_unlock(&moh_lock);
835
836         if (!mohclass) {
837                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
838                 return -1;
839         }
840
841         ast_set_flag(chan, AST_FLAG_MOH);
842         if (mohclass->total_files) {
843                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
844         } else
845                 return ast_activate_generator(chan, &mohgen, mohclass);
846 }
847
848 static void local_ast_moh_stop(struct ast_channel *chan)
849 {
850         ast_clear_flag(chan, AST_FLAG_MOH);
851         ast_deactivate_generator(chan);
852
853         if(chan->music_state) {
854                 if(chan->stream) {
855                         ast_closestream(chan->stream);
856                         chan->stream = NULL;
857                 }
858         }
859 }
860
861 static int load_moh_classes(void)
862 {
863         struct ast_config *cfg;
864         struct ast_variable *var;
865         char *data;
866         char *args;
867         int x = 0;
868         cfg = ast_load("musiconhold.conf");
869         if (cfg) {
870                 var = ast_variable_browse(cfg, "classes");
871                 while(var) {
872                         data = strchr(var->value, ':');
873                         if (data) {
874                                 *data = '\0';
875                                 data++;
876                                 args = strchr(data, ',');
877                                 if (args) {
878                                         *args = '\0';
879                                         args++;
880                                 }
881                                 if(!(get_mohbyname(var->name))) {
882                                         moh_register(var->name, var->value, data, args);
883                                         x++;
884                                 }
885                         }
886                         var = var->next;
887                 }
888                 var = ast_variable_browse(cfg, "moh_files");
889                 while(var) {
890                         if(!(get_mohbyname(var->name))) {
891                                 args = strchr(var->value, ',');
892                                 if (args) {
893                                         *args = '\0';
894                                         args++;
895                                 }
896                                 moh_register(var->name, "files", var->value, args);
897                                 x++;
898                         }
899                         var = var->next;
900                 }
901
902                 ast_destroy(cfg);
903         }
904         return x;
905 }
906
907 static void ast_moh_destroy(void)
908 {
909         struct mohclass *moh,*tmp;
910         char buff[8192];
911         int bytes, tbytes=0, stime = 0, pid = 0;
912         if (option_verbose > 1)
913                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
914         ast_mutex_lock(&moh_lock);
915         moh = mohclasses;
916
917         while(moh) {
918                 if (moh->pid) {
919                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
920                         stime = time(NULL);
921                         pid = moh->pid;
922                         moh->pid = 0;
923                         kill(pid, SIGKILL);
924                         while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
925                                 tbytes = tbytes + bytes;
926                         }
927                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
928                         close(moh->srcfd);
929                 }
930                 tmp = moh;
931                 moh = moh->next;
932                 free(tmp);
933         }
934         mohclasses = NULL;
935         ast_mutex_unlock(&moh_lock);
936 }
937
938
939 static void moh_on_off(int on) {
940         struct ast_channel *chan = ast_channel_walk_locked(NULL);
941         while(chan) {
942                 if(ast_test_flag(chan, AST_FLAG_MOH)) {
943                         if(on)
944                                 local_ast_moh_start(chan,NULL);
945                         else
946                                 ast_deactivate_generator(chan);
947                 }
948                 ast_mutex_unlock(&chan->lock);
949                 chan = ast_channel_walk_locked(chan);
950         }
951 }
952
953 static int moh_cli(int fd, int argc, char *argv[]) 
954 {
955         int x = 0;
956         moh_on_off(0);
957         ast_moh_destroy();
958         x = load_moh_classes();
959         moh_on_off(1);
960         ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
961         return 0;
962 }
963
964 static int cli_files_show(int fd, int argc, char *argv[])
965 {
966         int i;
967         struct mohclass *class;
968
969         ast_mutex_lock(&moh_lock);
970         for (class = mohclasses; class; class = class->next) {
971                 if (!class->total_files)
972                         continue;
973
974                 ast_cli(fd, "Class: %s\n", class->class);
975                 for (i = 0; i < class->total_files; i++)
976                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
977         }
978         ast_mutex_unlock(&moh_lock);
979
980         return 0;
981 }
982
983 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
984
985 static struct ast_cli_entry  cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL};
986
987
988 int load_module(void)
989 {
990         int res;
991         load_moh_classes();
992         ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
993         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
994         ast_register_atexit(ast_moh_destroy);
995         ast_cli_register(&cli_moh);
996         ast_cli_register(&cli_moh_files_show);
997         if (!res)
998                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
999         if (!res)
1000                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1001
1002         return res;
1003 }
1004
1005 int reload(void)
1006 {
1007     struct mohclass *moh = mohclasses;
1008     load_moh_classes();
1009     while(moh) {
1010         if (moh->total_files)
1011             moh_scan_files(moh);
1012         moh = moh->next;
1013     }
1014     return 0;
1015 }
1016
1017
1018 int unload_module(void)
1019 {
1020         return -1;
1021 }
1022
1023 char *description(void)
1024 {
1025         return "Music On Hold Resource";
1026 }
1027
1028 int usecount(void)
1029 {
1030         /* Never allow Music On Hold to be unloaded
1031            unresolve needed symbols in the dialer */
1032 #if 0
1033         int res;
1034         STANDARD_USECOUNT(res);
1035         return res;
1036 #else
1037         return 1;
1038 #endif
1039 }
1040
1041 char *key()
1042 {
1043         return ASTERISK_GPL_KEY;
1044 }