Migrate a large number of AMI events over to Stasis-Core
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Routines implementing music on hold
22  * 
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*! \li \ref res_musiconhold.c uses the configuration file \ref musiconhold.conf
27  * \addtogroup configuration_file Configuration Files
28  */
29
30 /*! 
31  * \page musiconhold.conf musiconhold.conf
32  * \verbinclude musiconhold.conf.sample
33  */
34
35 /*** MODULEINFO
36         <conflict>win32</conflict>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include <ctype.h>
45 #include <signal.h>
46 #include <sys/time.h>
47 #include <sys/signal.h>
48 #include <netinet/in.h>
49 #include <sys/stat.h>
50 #include <dirent.h>
51
52 #ifdef SOLARIS
53 #include <thread.h>
54 #endif
55
56 #include "asterisk/lock.h"
57 #include "asterisk/file.h"
58 #include "asterisk/channel.h"
59 #include "asterisk/pbx.h"
60 #include "asterisk/app.h"
61 #include "asterisk/module.h"
62 #include "asterisk/translate.h"
63 #include "asterisk/say.h"
64 #include "asterisk/musiconhold.h"
65 #include "asterisk/config.h"
66 #include "asterisk/utils.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/stringfields.h"
69 #include "asterisk/linkedlists.h"
70 #include "asterisk/stasis.h"
71 #include "asterisk/stasis_channels.h"
72 #include "asterisk/paths.h"
73 #include "asterisk/astobj2.h"
74 #include "asterisk/timing.h"
75 #include "asterisk/time.h"
76 #include "asterisk/poll-compat.h"
77
78 #define INITIAL_NUM_FILES   8
79 #define HANDLE_REF      1
80 #define DONT_UNREF      0
81
82 /*** DOCUMENTATION
83         <application name="MusicOnHold" language="en_US">
84                 <synopsis>
85                         Play Music On Hold indefinitely.
86                 </synopsis>
87                 <syntax>
88                         <parameter name="class" required="true" />
89                         <parameter name="duration" />
90                 </syntax>
91                 <description>
92                         <para>Plays hold music specified by class. If omitted, the default music
93                         source for the channel will be used. Change the default class with
94                         Set(CHANNEL(musicclass)=...). If duration is given, hold music will be played
95                         specified number of seconds. If duration is ommited, music plays indefinitely.
96                         Returns <literal>0</literal> when done, <literal>-1</literal> on hangup.</para>
97                         <para>This application does not automatically answer and should be preceeded by
98                         an application such as Answer() or Progress().</para>
99                 </description>
100         </application>
101         <application name="WaitMusicOnHold" language="en_US">
102                 <synopsis>
103                         Wait, playing Music On Hold.
104                 </synopsis>
105                 <syntax>
106                         <parameter name="delay" required="true" />
107                 </syntax>
108                 <description>
109                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
110                         <para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
111                         or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
112                         with no sound.</para>
113                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
114                 </description>
115         </application>
116         <application name="SetMusicOnHold" language="en_US">
117                 <synopsis>
118                         Set default Music On Hold class.
119                 </synopsis>
120                 <syntax>
121                         <parameter name="class" required="yes" />
122                 </syntax>
123                 <description>
124                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
125                         <para>Sets the default class for music on hold for a given channel.
126                         When music on hold is activated, this class will be used to select which
127                         music is played.</para>
128                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
129                 </description>
130         </application>
131         <application name="StartMusicOnHold" language="en_US">
132                 <synopsis>
133                         Play Music On Hold.
134                 </synopsis>
135                 <syntax>
136                         <parameter name="class" required="true" />
137                 </syntax>
138                 <description>
139                         <para>Starts playing music on hold, uses default music class for channel.
140                         Starts playing music specified by class. If omitted, the default music
141                         source for the channel will be used. Always returns <literal>0</literal>.</para>
142                 </description>
143         </application>
144         <application name="StopMusicOnHold" language="en_US">
145                 <synopsis>
146                         Stop playing Music On Hold.
147                 </synopsis>
148                 <syntax />
149                 <description>
150                         <para>Stops playing music on hold.</para>
151                 </description>
152         </application>
153  ***/
154
155 static const char play_moh[] = "MusicOnHold";
156 static const char wait_moh[] = "WaitMusicOnHold";
157 static const char set_moh[] = "SetMusicOnHold";
158 static const char start_moh[] = "StartMusicOnHold";
159 static const char stop_moh[] = "StopMusicOnHold";
160
161 static int respawn_time = 20;
162
163 struct moh_files_state {
164         /*! Holds a reference to the MOH class. */
165         struct mohclass *class;
166         char name[MAX_MUSICCLASS];
167         struct ast_format origwfmt;
168         struct ast_format mohwfmt;
169         int announcement;
170         int samples;
171         int sample_queue;
172         int pos;
173         int save_pos;
174         int save_total;
175         char save_pos_filename[PATH_MAX];
176 };
177
178 #define MOH_QUIET               (1 << 0)
179 #define MOH_SINGLE              (1 << 1)
180 #define MOH_CUSTOM              (1 << 2)
181 #define MOH_RANDOMIZE           (1 << 3)
182 #define MOH_SORTALPHA           (1 << 4)
183
184 #define MOH_CACHERTCLASSES      (1 << 5)        /*!< Should we use a separate instance of MOH for each user or not */
185 #define MOH_ANNOUNCEMENT        (1 << 6)                        /*!< Do we play announcement files between songs on this channel? */
186
187 /* Custom astobj2 flag */
188 #define MOH_NOTDELETED          (1 << 30)       /*!< Find only records that aren't deleted? */
189
190 static struct ast_flags global_flags[1] = {{0}};        /*!< global MOH_ flags */
191
192 struct mohclass {
193         char name[MAX_MUSICCLASS];
194         char dir[256];
195         char args[256];
196         char announcement[256];
197         char mode[80];
198         char digit;
199         /*! A dynamically sized array to hold the list of filenames in "files" mode */
200         char **filearray;
201         /*! The current size of the filearray */
202         int allowed_files;
203         /*! The current number of files loaded into the filearray */
204         int total_files;
205         unsigned int flags;
206         /*! The format from the MOH source, not applicable to "files" mode */
207         struct ast_format format;
208         /*! The pid of the external application delivering MOH */
209         int pid;
210         time_t start;
211         pthread_t thread;
212         /*! Source of audio */
213         int srcfd;
214         /*! Generic timer */
215         struct ast_timer *timer;
216         /*! Created on the fly, from RT engine */
217         unsigned int realtime:1;
218         unsigned int delete:1;
219         AST_LIST_HEAD_NOLOCK(, mohdata) members;
220         AST_LIST_ENTRY(mohclass) list;
221 };
222
223 struct mohdata {
224         int pipe[2];
225         struct ast_format origwfmt;
226         struct mohclass *parent;
227         struct ast_frame f;
228         AST_LIST_ENTRY(mohdata) list;
229 };
230
231 static struct ao2_container *mohclasses;
232
233 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
234 #define MPG_123 "/usr/bin/mpg123"
235 #define MAX_MP3S 256
236
237 static int reload(void);
238
239 #define mohclass_ref(class,string)   (ao2_t_ref((class), +1, (string)), class)
240
241 #ifndef REF_DEBUG
242 #define mohclass_unref(class,string) (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL)
243 #else
244 #define mohclass_unref(class,string) _mohclass_unref(class, string, __FILE__,__LINE__,__PRETTY_FUNCTION__)
245 static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag, const char *file, int line, const char *funcname)
246 {
247         struct mohclass *dup;
248         if ((dup = ao2_find(mohclasses, class, OBJ_POINTER))) {
249                 if (__ao2_ref_debug(dup, -1, (char *) tag, (char *) file, line, funcname) == 2) {
250                         FILE *ref = fopen("/tmp/refs", "a");
251                         if (ref) {
252                                 fprintf(ref, "%p =1   %s:%d:%s (%s) BAD ATTEMPT!\n", class, file, line, funcname, tag);
253                                 fclose(ref);
254                         }
255                         ast_log(LOG_WARNING, "Attempt to unref mohclass %p (%s) when only 1 ref remained, and class is still in a container! (at %s:%d (%s))\n",
256                                 class, class->name, file, line, funcname);
257                 } else {
258                         ao2_ref(class, -1);
259                 }
260         } else {
261                 ao2_t_ref(class, -1, (char *) tag);
262         }
263         return NULL;
264 }
265 #endif
266
267 static void moh_files_release(struct ast_channel *chan, void *data)
268 {
269         struct moh_files_state *state;
270
271         if (!chan || !ast_channel_music_state(chan)) {
272                 return;
273         }
274
275         state = ast_channel_music_state(chan);
276
277         if (ast_channel_stream(chan)) {
278                 ast_closestream(ast_channel_stream(chan));
279                 ast_channel_stream_set(chan, NULL);
280         }
281         
282         ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
283
284         ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */
285         if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) {
286                 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt));
287         }
288
289         state->save_pos = state->pos;
290         state->announcement = 0;
291
292         state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
293 }
294
295 static int ast_moh_files_next(struct ast_channel *chan) 
296 {
297         struct moh_files_state *state = ast_channel_music_state(chan);
298         int tries;
299
300         /* Discontinue a stream if it is running already */
301         if (ast_channel_stream(chan)) {
302                 ast_closestream(ast_channel_stream(chan));
303                 ast_channel_stream_set(chan, NULL);
304         }
305
306         if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) {
307                 state->announcement = 1;
308                 if (ast_openstream_full(chan, state->class->announcement, ast_channel_language(chan), 1)) {
309                         ast_debug(1, "%s Opened announcement '%s'\n", ast_channel_name(chan), state->class->announcement);
310                         return 0;
311                 }
312         } else {
313                 state->announcement = 0;
314         }
315
316         if (!state->class->total_files) {
317                 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
318                 return -1;
319         }
320
321         if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
322                 /* First time so lets play the file. */
323                 state->save_pos = -1;
324         } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) {
325                 /* If a specific file has been saved confirm it still exists and that it is still valid */
326                 state->pos = state->save_pos;
327                 state->save_pos = -1;
328         } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
329                 /* Get a random file and ensure we can open it */
330                 for (tries = 0; tries < 20; tries++) {
331                         state->pos = ast_random() % state->class->total_files;
332                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) {
333                                 break;
334                         }
335                 }
336                 state->save_pos = -1;
337                 state->samples = 0;
338         } else {
339                 /* This is easy, just increment our position and make sure we don't exceed the total file count */
340                 state->pos++;
341                 state->pos %= state->class->total_files;
342                 state->save_pos = -1;
343                 state->samples = 0;
344         }
345
346         for (tries = 0; tries < state->class->total_files; ++tries) {
347                 if (ast_openstream_full(chan, state->class->filearray[state->pos], ast_channel_language(chan), 1)) {
348                         break;
349                 }
350
351                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
352                 state->pos++;
353                 state->pos %= state->class->total_files;
354         }
355
356         if (tries == state->class->total_files) {
357                 return -1;
358         }
359
360         /* Record the pointer to the filename for position resuming later */
361         ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename));
362
363         ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->class->filearray[state->pos]);
364
365         if (state->samples) {
366                 size_t loc;
367                 /* seek *SHOULD* be good since it's from a known location */
368                 ast_seekstream(ast_channel_stream(chan), state->samples, SEEK_SET);
369                 /* if the seek failed then recover because if there is not a valid read,
370                  * moh_files_generate will return -1 and MOH will stop */
371                 loc = ast_tellstream(ast_channel_stream(chan));
372                 if (state->samples > loc && loc) {
373                         /* seek one sample from the end for one guaranteed valid read */
374                         ast_seekstream(ast_channel_stream(chan), 1, SEEK_END);
375                 }
376         }
377
378         return 0;
379 }
380
381 static struct ast_frame *moh_files_readframe(struct ast_channel *chan)
382 {
383         struct ast_frame *f = NULL;
384
385         if (!(ast_channel_stream(chan) && (f = ast_readframe(ast_channel_stream(chan))))) {
386                 if (!ast_moh_files_next(chan))
387                         f = ast_readframe(ast_channel_stream(chan));
388         }
389
390         return f;
391 }
392
393 static void moh_files_write_format_change(struct ast_channel *chan, void *data)
394 {
395         struct moh_files_state *state = ast_channel_music_state(chan);
396
397         /* In order to prevent a recursive call to this function as a result
398          * of setting the moh write format back on the channel. Clear
399          * the moh write format before setting the write format on the channel.*/
400         if (&state->origwfmt.id) {
401                 struct ast_format tmp;
402
403                 ast_format_copy(&tmp, ast_channel_writeformat(chan));
404                 if (state->mohwfmt.id) {
405                         ast_format_clear(&state->origwfmt);
406                         ast_set_write_format(chan, &state->mohwfmt);
407                 }
408                 ast_format_copy(&state->origwfmt, &tmp);
409         }
410 }
411
412 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
413 {
414         struct moh_files_state *state = ast_channel_music_state(chan);
415         struct ast_frame *f = NULL;
416         int res = 0;
417
418         state->sample_queue += samples;
419
420         while (state->sample_queue > 0) {
421                 ast_channel_lock(chan);
422                 if ((f = moh_files_readframe(chan))) {
423                         /* We need to be sure that we unlock
424                          * the channel prior to calling
425                          * ast_write. Otherwise, the recursive locking
426                          * that occurs can cause deadlocks when using
427                          * indirect channels, like local channels
428                          */
429                         ast_channel_unlock(chan);
430                         state->samples += f->samples;
431                         state->sample_queue -= f->samples;
432                         if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
433                                 ast_format_copy(&state->mohwfmt, &f->subclass.format);
434                         }
435                         res = ast_write(chan, f);
436                         ast_frfree(f);
437                         if (res < 0) {
438                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
439                                 return -1;
440                         }
441                 } else {
442                         ast_channel_unlock(chan);
443                         return -1;      
444                 }
445         }
446         return res;
447 }
448
449 static void *moh_files_alloc(struct ast_channel *chan, void *params)
450 {
451         struct moh_files_state *state;
452         struct mohclass *class = params;
453
454         if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
455                 ast_channel_music_state_set(chan, state);
456                 ast_module_ref(ast_module_info->self);
457         } else {
458                 state = ast_channel_music_state(chan);
459                 if (!state) {
460                         return NULL;
461                 }
462                 if (state->class) {
463                         mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
464                         ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
465                 }
466         }
467
468         /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because
469          * malloc may allocate a different class to the same memory block.  This
470          * might only happen when two reloads are generated in a short period of
471          * time, but it's still important to protect against.
472          * PROG: Compare the quick operation first, to save CPU. */
473         if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
474                 memset(state, 0, sizeof(*state));
475                 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
476                         state->pos = ast_random() % class->total_files;
477                 }
478         }
479
480         state->class = mohclass_ref(class, "Reffing music class for channel");
481         ast_format_copy(&state->origwfmt, ast_channel_writeformat(chan));
482         ast_format_copy(&state->mohwfmt, ast_channel_writeformat(chan));
483
484         /* For comparison on restart of MOH (see above) */
485         ast_copy_string(state->name, class->name, sizeof(state->name));
486         state->save_total = class->total_files;
487
488         ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, ast_channel_name(chan));
489         
490         return ast_channel_music_state(chan);
491 }
492
493 static int moh_digit_match(void *obj, void *arg, int flags)
494 {
495         char *digit = arg;
496         struct mohclass *class = obj;
497
498         return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
499 }
500
501 /*! \note This function should be called with the mohclasses list locked */
502 static struct mohclass *get_mohbydigit(char digit)
503 {
504         return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
505 }
506
507 static void moh_handle_digit(struct ast_channel *chan, char digit)
508 {
509         struct mohclass *class;
510         const char *classname = NULL;
511
512         if ((class = get_mohbydigit(digit))) {
513                 classname = ast_strdupa(class->name);
514                 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
515                 ast_channel_musicclass_set(chan, classname);
516                 ast_moh_stop(chan);
517                 ast_moh_start(chan, classname, NULL);
518         }
519 }
520
521 static struct ast_generator moh_file_stream = 
522 {
523         .alloc    = moh_files_alloc,
524         .release  = moh_files_release,
525         .generate = moh_files_generator,
526         .digit    = moh_handle_digit,
527         .write_format_change = moh_files_write_format_change,
528 };
529
530 static int spawn_mp3(struct mohclass *class)
531 {
532         int fds[2];
533         int files = 0;
534         char fns[MAX_MP3S][80];
535         char *argv[MAX_MP3S + 50];
536         char xargs[256];
537         char *argptr;
538         int argc = 0;
539         DIR *dir = NULL;
540         struct dirent *de;
541
542         
543         if (!strcasecmp(class->dir, "nodir")) {
544                 files = 1;
545         } else {
546                 dir = opendir(class->dir);
547                 if (!dir && strncasecmp(class->dir, "http://", 7)) {
548                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
549                         return -1;
550                 }
551         }
552
553         if (!ast_test_flag(class, MOH_CUSTOM)) {
554                 argv[argc++] = "mpg123";
555                 argv[argc++] = "-q";
556                 argv[argc++] = "-s";
557                 argv[argc++] = "--mono";
558                 argv[argc++] = "-r";
559                 argv[argc++] = "8000";
560                 
561                 if (!ast_test_flag(class, MOH_SINGLE)) {
562                         argv[argc++] = "-b";
563                         argv[argc++] = "2048";
564                 }
565                 
566                 argv[argc++] = "-f";
567                 
568                 if (ast_test_flag(class, MOH_QUIET))
569                         argv[argc++] = "4096";
570                 else
571                         argv[argc++] = "8192";
572                 
573                 /* Look for extra arguments and add them to the list */
574                 ast_copy_string(xargs, class->args, sizeof(xargs));
575                 argptr = xargs;
576                 while (!ast_strlen_zero(argptr)) {
577                         argv[argc++] = argptr;
578                         strsep(&argptr, ",");
579                 }
580         } else  {
581                 /* Format arguments for argv vector */
582                 ast_copy_string(xargs, class->args, sizeof(xargs));
583                 argptr = xargs;
584                 while (!ast_strlen_zero(argptr)) {
585                         argv[argc++] = argptr;
586                         strsep(&argptr, " ");
587                 }
588         }
589
590         if (!strncasecmp(class->dir, "http://", 7)) {
591                 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
592                 argv[argc++] = fns[files];
593                 files++;
594         } else if (dir) {
595                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
596                         if ((strlen(de->d_name) > 3) && 
597                             ((ast_test_flag(class, MOH_CUSTOM) && 
598                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
599                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
600                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
601                                 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
602                                 argv[argc++] = fns[files];
603                                 files++;
604                         }
605                 }
606         }
607         argv[argc] = NULL;
608         if (dir) {
609                 closedir(dir);
610         }
611         if (pipe(fds)) {        
612                 ast_log(LOG_WARNING, "Pipe failed\n");
613                 return -1;
614         }
615         if (!files) {
616                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
617                 close(fds[0]);
618                 close(fds[1]);
619                 return -1;
620         }
621         if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
622                 sleep(respawn_time - (time(NULL) - class->start));
623         }
624
625         time(&class->start);
626         class->pid = ast_safe_fork(0);
627         if (class->pid < 0) {
628                 close(fds[0]);
629                 close(fds[1]);
630                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
631                 return -1;
632         }
633         if (!class->pid) {
634                 if (ast_opt_high_priority)
635                         ast_set_priority(0);
636
637                 close(fds[0]);
638                 /* Stdout goes to pipe */
639                 dup2(fds[1], STDOUT_FILENO);
640
641                 /* Close everything else */
642                 ast_close_fds_above_n(STDERR_FILENO);
643
644                 /* Child */
645                 if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
646                         ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
647                         _exit(1);
648                 }
649                 setpgid(0, getpid());
650                 if (ast_test_flag(class, MOH_CUSTOM)) {
651                         execv(argv[0], argv);
652                 } else {
653                         /* Default install is /usr/local/bin */
654                         execv(LOCAL_MPG_123, argv);
655                         /* Many places have it in /usr/bin */
656                         execv(MPG_123, argv);
657                         /* Check PATH as a last-ditch effort */
658                         execvp("mpg123", argv);
659                 }
660                 /* Can't use logger, since log FDs are closed */
661                 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
662                 close(fds[1]);
663                 _exit(1);
664         } else {
665                 /* Parent */
666                 close(fds[1]);
667         }
668         return fds[0];
669 }
670
671 static void *monmp3thread(void *data)
672 {
673 #define MOH_MS_INTERVAL         100
674
675         struct mohclass *class = data;
676         struct mohdata *moh;
677         short sbuf[8192];
678         int res = 0, res2;
679         int len;
680         struct timeval deadline, tv_tmp;
681
682         deadline.tv_sec = 0;
683         deadline.tv_usec = 0;
684         for(;/* ever */;) {
685                 pthread_testcancel();
686                 /* Spawn mp3 player if it's not there */
687                 if (class->srcfd < 0) {
688                         if ((class->srcfd = spawn_mp3(class)) < 0) {
689                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
690                                 /* Try again later */
691                                 sleep(500);
692                                 continue;
693                         }
694                 }
695                 if (class->timer) {
696                         struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, };
697
698 #ifdef SOLARIS
699                         thr_yield();
700 #endif
701                         /* Pause some amount of time */
702                         if (ast_poll(&pfd, 1, -1) > 0) {
703                                 if (ast_timer_ack(class->timer, 1) < 0) {
704                                         ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
705                                         return NULL;
706                                 }
707                                 res = 320;
708                         } else {
709                                 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
710                                 res = 0;
711                         }
712                         pthread_testcancel();
713                 } else {
714                         long delta;
715                         /* Reliable sleep */
716                         tv_tmp = ast_tvnow();
717                         if (ast_tvzero(deadline))
718                                 deadline = tv_tmp;
719                         delta = ast_tvdiff_ms(tv_tmp, deadline);
720                         if (delta < MOH_MS_INTERVAL) {  /* too early */
721                                 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000));     /* next deadline */
722                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
723                                 pthread_testcancel();
724                         } else {
725                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
726                                 deadline = tv_tmp;
727                         }
728                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
729                 }
730                 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
731                         continue;
732                 /* Read mp3 audio */
733                 len = ast_codec_get_len(&class->format, res);
734
735                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
736                         if (!res2) {
737                                 close(class->srcfd);
738                                 class->srcfd = -1;
739                                 pthread_testcancel();
740                                 if (class->pid > 1) {
741                                         do {
742                                                 if (killpg(class->pid, SIGHUP) < 0) {
743                                                         if (errno == ESRCH) {
744                                                                 break;
745                                                         }
746                                                         ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
747                                                 }
748                                                 usleep(100000);
749                                                 if (killpg(class->pid, SIGTERM) < 0) {
750                                                         if (errno == ESRCH) {
751                                                                 break;
752                                                         }
753                                                         ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
754                                                 }
755                                                 usleep(100000);
756                                                 if (killpg(class->pid, SIGKILL) < 0) {
757                                                         if (errno == ESRCH) {
758                                                                 break;
759                                                         }
760                                                         ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
761                                                 }
762                                         } while (0);
763                                         class->pid = 0;
764                                 }
765                         } else {
766                                 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
767                         }
768                         continue;
769                 }
770
771                 pthread_testcancel();
772
773                 ao2_lock(class);
774                 AST_LIST_TRAVERSE(&class->members, moh, list) {
775                         /* Write data */
776                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
777                                 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
778                         }
779                 }
780                 ao2_unlock(class);
781         }
782         return NULL;
783 }
784
785 static int play_moh_exec(struct ast_channel *chan, const char *data)
786 {
787         char *parse;
788         char *class;
789         int timeout = -1;
790         int res;
791         AST_DECLARE_APP_ARGS(args,
792                 AST_APP_ARG(class);
793                 AST_APP_ARG(duration);
794         );
795
796         parse = ast_strdupa(data);
797
798         AST_STANDARD_APP_ARGS(args, parse);
799
800         if (!ast_strlen_zero(args.duration)) {
801                 if (sscanf(args.duration, "%30d", &timeout) == 1) {
802                         timeout *= 1000;
803                 } else {
804                         ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
805                 }
806         }
807
808         class = S_OR(args.class, NULL);
809         if (ast_moh_start(chan, class, NULL)) {
810                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
811                 return 0;
812         }
813
814         if (timeout > 0)
815                 res = ast_safe_sleep(chan, timeout);
816         else {
817                 while (!(res = ast_safe_sleep(chan, 10000)));
818         }
819
820         ast_moh_stop(chan);
821
822         return res;
823 }
824
825 static int wait_moh_exec(struct ast_channel *chan, const char *data)
826 {
827         static int deprecation_warning = 0;
828         int res;
829
830         if (!deprecation_warning) {
831                 deprecation_warning = 1;
832                 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
833         }
834
835         if (!data || !atoi(data)) {
836                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
837                 return -1;
838         }
839         if (ast_moh_start(chan, NULL, NULL)) {
840                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan));
841                 return 0;
842         }
843         res = ast_safe_sleep(chan, atoi(data) * 1000);
844         ast_moh_stop(chan);
845         return res;
846 }
847
848 static int set_moh_exec(struct ast_channel *chan, const char *data)
849 {
850         static int deprecation_warning = 0;
851
852         if (!deprecation_warning) {
853                 deprecation_warning = 1;
854                 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
855         }
856
857         if (ast_strlen_zero(data)) {
858                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
859                 return -1;
860         }
861         ast_channel_musicclass_set(chan, data);
862         return 0;
863 }
864
865 static int start_moh_exec(struct ast_channel *chan, const char *data)
866 {
867         char *parse;
868         char *class;
869         AST_DECLARE_APP_ARGS(args,
870                 AST_APP_ARG(class);
871         );
872
873         parse = ast_strdupa(data);
874
875         AST_STANDARD_APP_ARGS(args, parse);
876
877         class = S_OR(args.class, NULL);
878         if (ast_moh_start(chan, class, NULL)) 
879                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
880
881         return 0;
882 }
883
884 static int stop_moh_exec(struct ast_channel *chan, const char *data)
885 {
886         ast_moh_stop(chan);
887
888         return 0;
889 }
890
891 #define get_mohbyname(a,b,c)    _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
892
893 static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, const char *file, int lineno, const char *funcname)
894 {
895         struct mohclass *moh = NULL;
896         struct mohclass tmp_class = {
897                 .flags = 0,
898         };
899
900         ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
901
902 #ifdef REF_DEBUG
903         moh = __ao2_find_debug(mohclasses, &tmp_class, flags,
904                 "get_mohbyname", file, lineno, funcname);
905 #else
906         moh = __ao2_find(mohclasses, &tmp_class, flags);
907 #endif
908
909         if (!moh && warn) {
910                 ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
911         }
912
913         return moh;
914 }
915
916 static struct mohdata *mohalloc(struct mohclass *cl)
917 {
918         struct mohdata *moh;
919         long flags;
920
921         if (!(moh = ast_calloc(1, sizeof(*moh))))
922                 return NULL;
923
924         if (pipe(moh->pipe)) {
925                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
926                 ast_free(moh);
927                 return NULL;
928         }
929
930         /* Make entirely non-blocking */
931         flags = fcntl(moh->pipe[0], F_GETFL);
932         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
933         flags = fcntl(moh->pipe[1], F_GETFL);
934         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
935
936         moh->f.frametype = AST_FRAME_VOICE;
937         ast_format_copy(&moh->f.subclass.format, &cl->format);
938         moh->f.offset = AST_FRIENDLY_OFFSET;
939
940         moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
941
942         ao2_lock(cl);
943         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
944         ao2_unlock(cl);
945         
946         return moh;
947 }
948
949 static void moh_release(struct ast_channel *chan, void *data)
950 {
951         struct mohdata *moh = data;
952         struct mohclass *class = moh->parent;
953         struct ast_format oldwfmt;
954
955         ao2_lock(class);
956         AST_LIST_REMOVE(&moh->parent->members, moh, list);      
957         ao2_unlock(class);
958         
959         close(moh->pipe[0]);
960         close(moh->pipe[1]);
961
962         ast_format_copy(&oldwfmt, &moh->origwfmt);
963
964         moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
965
966         ast_free(moh);
967
968         if (chan) {
969                 struct moh_files_state *state;
970
971                 state = ast_channel_music_state(chan);
972                 if (state && state->class) {
973                         state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
974                 }
975                 if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) {
976                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
977                                         ast_channel_name(chan), ast_getformatname(&oldwfmt));
978                 }
979
980                 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
981         }
982 }
983
984 static void *moh_alloc(struct ast_channel *chan, void *params)
985 {
986         struct mohdata *res;
987         struct mohclass *class = params;
988         struct moh_files_state *state;
989
990         /* Initiating music_state for current channel. Channel should know name of moh class */
991         if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
992                 ast_channel_music_state_set(chan, state);
993                 ast_module_ref(ast_module_info->self);
994         } else {
995                 state = ast_channel_music_state(chan);
996                 if (!state) {
997                         return NULL;
998                 }
999                 if (state->class) {
1000                         mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
1001                         ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
1002                 }
1003                 memset(state, 0, sizeof(*state));
1004         }
1005
1006         if ((res = mohalloc(class))) {
1007                 ast_format_copy(&res->origwfmt, ast_channel_writeformat(chan));
1008                 if (ast_set_write_format(chan, &class->format)) {
1009                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format));
1010                         moh_release(NULL, res);
1011                         res = NULL;
1012                 } else {
1013                         state->class = mohclass_ref(class, "Placing reference into state container");
1014                 }
1015                 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, ast_channel_name(chan));
1016         }
1017         return res;
1018 }
1019
1020 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
1021 {
1022         struct mohdata *moh = data;
1023         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
1024         int res;
1025
1026         len = ast_codec_get_len(&moh->parent->format, samples);
1027
1028         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
1029                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
1030                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
1031         }
1032         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
1033         if (res <= 0)
1034                 return 0;
1035
1036         moh->f.datalen = res;
1037         moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
1038         moh->f.samples = ast_codec_get_samples(&moh->f);
1039
1040         if (ast_write(chan, &moh->f) < 0) {
1041                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1042                 return -1;
1043         }
1044
1045         return 0;
1046 }
1047
1048 static struct ast_generator mohgen = {
1049         .alloc    = moh_alloc,
1050         .release  = moh_release,
1051         .generate = moh_generate,
1052         .digit    = moh_handle_digit,
1053 };
1054
1055 static int moh_add_file(struct mohclass *class, const char *filepath)
1056 {
1057         if (!class->allowed_files) {
1058                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
1059                         return -1;
1060                 class->allowed_files = INITIAL_NUM_FILES;
1061         } else if (class->total_files == class->allowed_files) {
1062                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
1063                         class->allowed_files = 0;
1064                         class->total_files = 0;
1065                         return -1;
1066                 }
1067                 class->allowed_files *= 2;
1068         }
1069
1070         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
1071                 return -1;
1072
1073         class->total_files++;
1074
1075         return 0;
1076 }
1077
1078 static int moh_sort_compare(const void *i1, const void *i2)
1079 {
1080         char *s1, *s2;
1081
1082         s1 = ((char **)i1)[0];
1083         s2 = ((char **)i2)[0];
1084
1085         return strcasecmp(s1, s2);
1086 }
1087
1088 static int moh_scan_files(struct mohclass *class) {
1089
1090         DIR *files_DIR;
1091         struct dirent *files_dirent;
1092         char dir_path[PATH_MAX];
1093         char path[PATH_MAX];
1094         char filepath[PATH_MAX];
1095         char *ext;
1096         struct stat statbuf;
1097         int i;
1098
1099         if (class->dir[0] != '/') {
1100                 ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path));
1101                 strncat(dir_path, "/", sizeof(dir_path) - 1);
1102                 strncat(dir_path, class->dir, sizeof(dir_path) - 1);
1103         } else {
1104                 ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1105         }
1106         ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1107         files_DIR = opendir(dir_path);
1108         if (!files_DIR) {
1109                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1110                 return -1;
1111         }
1112
1113         for (i = 0; i < class->total_files; i++) {
1114                 ast_free(class->filearray[i]);
1115         }
1116         class->total_files = 0;
1117
1118         if (!getcwd(path, sizeof(path))) {
1119                 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
1120                 closedir(files_DIR);
1121                 return -1;
1122         }
1123         if (chdir(dir_path) < 0) {
1124                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1125                 closedir(files_DIR);
1126                 return -1;
1127         }
1128         while ((files_dirent = readdir(files_DIR))) {
1129                 /* The file name must be at least long enough to have the file type extension */
1130                 if ((strlen(files_dirent->d_name) < 4))
1131                         continue;
1132
1133                 /* Skip files that starts with a dot */
1134                 if (files_dirent->d_name[0] == '.')
1135                         continue;
1136
1137                 /* Skip files without extensions... they are not audio */
1138                 if (!strchr(files_dirent->d_name, '.'))
1139                         continue;
1140
1141                 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
1142
1143                 if (stat(filepath, &statbuf))
1144                         continue;
1145
1146                 if (!S_ISREG(statbuf.st_mode))
1147                         continue;
1148
1149                 if ((ext = strrchr(filepath, '.')))
1150                         *ext = '\0';
1151
1152                 /* if the file is present in multiple formats, ensure we only put it into the list once */
1153                 for (i = 0; i < class->total_files; i++)
1154                         if (!strcmp(filepath, class->filearray[i]))
1155                                 break;
1156
1157                 if (i == class->total_files) {
1158                         if (moh_add_file(class, filepath))
1159                                 break;
1160                 }
1161         }
1162
1163         closedir(files_DIR);
1164         if (chdir(path) < 0) {
1165                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1166                 return -1;
1167         }
1168         if (ast_test_flag(class, MOH_SORTALPHA))
1169                 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
1170         return class->total_files;
1171 }
1172
1173 static int init_files_class(struct mohclass *class)
1174 {
1175         int res;
1176
1177         res = moh_scan_files(class);
1178
1179         if (res < 0) {
1180                 return -1;
1181         }
1182
1183         if (!res) {
1184                 ast_verb(3, "Files not found in %s for moh class:%s\n",
1185                         class->dir, class->name);
1186                 return -1;
1187         }
1188
1189 #if 0
1190         /* XXX This isn't correct.  Args is an application for custom mode. XXX */
1191         if (strchr(class->args, 'r')) {
1192                 ast_set_flag(class, MOH_RANDOMIZE);
1193         }
1194 #endif
1195
1196         return 0;
1197 }
1198
1199 static void moh_rescan_files(void) {
1200         struct ao2_iterator i;
1201         struct mohclass *c;
1202
1203         i = ao2_iterator_init(mohclasses, 0);
1204
1205         while ((c = ao2_iterator_next(&i))) {
1206                 if (!strcasecmp(c->mode, "files")) {
1207                         moh_scan_files(c);
1208                 }
1209                 ao2_ref(c, -1);
1210         }
1211
1212         ao2_iterator_destroy(&i);
1213 }
1214
1215 static int moh_diff(struct mohclass *old, struct mohclass *new)
1216 {
1217         if (!old || !new) {
1218                 return -1;
1219         }
1220
1221         if (strcmp(old->dir, new->dir)) {
1222                 return -1;
1223         } else if (strcmp(old->mode, new->mode)) {
1224                 return -1;
1225         } else if (strcmp(old->args, new->args)) {
1226                 return -1;
1227         } else if (old->flags != new->flags) {
1228                 return -1;
1229         }
1230
1231         return 0;
1232 }
1233
1234 static int init_app_class(struct mohclass *class)
1235 {
1236         if (!strcasecmp(class->mode, "custom")) {
1237                 ast_set_flag(class, MOH_CUSTOM);
1238         } else if (!strcasecmp(class->mode, "mp3nb")) {
1239                 ast_set_flag(class, MOH_SINGLE);
1240         } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1241                 ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1242         } else if (!strcasecmp(class->mode, "quietmp3")) {
1243                 ast_set_flag(class, MOH_QUIET);
1244         }
1245
1246         class->srcfd = -1;
1247
1248         if (!(class->timer = ast_timer_open())) {
1249                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1250                 return -1;
1251         }
1252         if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1253                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1254                 ast_timer_close(class->timer);
1255                 class->timer = NULL;
1256         }
1257
1258         if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1259                 ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1260                 if (class->timer) {
1261                         ast_timer_close(class->timer);
1262                         class->timer = NULL;
1263                 }
1264                 return -1;
1265         }
1266
1267         return 0;
1268 }
1269
1270 /*!
1271  * \note This function owns the reference it gets to moh if unref is true
1272  */
1273 #define moh_register(a,b,c)     _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1274 static int _moh_register(struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
1275 {
1276         struct mohclass *mohclass = NULL;
1277
1278         mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1279
1280         if (mohclass && !moh_diff(mohclass, moh)) {
1281                 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1282                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1283                 if (unref) {
1284                         moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1285                 }
1286                 return -1;
1287         } else if (mohclass) {
1288                 /* Found a class, but it's different from the one being registered */
1289                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1290         }
1291
1292         time(&moh->start);
1293         moh->start -= respawn_time;
1294
1295         if (!strcasecmp(moh->mode, "files")) {
1296                 if (init_files_class(moh)) {
1297                         if (unref) {
1298                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1299                         }
1300                         return -1;
1301                 }
1302         } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 
1303                         !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 
1304                         !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1305                 if (init_app_class(moh)) {
1306                         if (unref) {
1307                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1308                         }
1309                         return -1;
1310                 }
1311         } else {
1312                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1313                 if (unref) {
1314                         moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1315                 }
1316                 return -1;
1317         }
1318
1319         ao2_t_link(mohclasses, moh, "Adding class to container");
1320
1321         if (unref) {
1322                 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1323         }
1324
1325         return 0;
1326 }
1327
1328 static void local_ast_moh_cleanup(struct ast_channel *chan)
1329 {
1330         struct moh_files_state *state = ast_channel_music_state(chan);
1331
1332         if (state) {
1333                 if (state->class) {
1334                         /* This should never happen.  We likely just leaked some resource. */
1335                         state->class =
1336                                 mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1337                         ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1338                 }
1339                 ast_free(ast_channel_music_state(chan));
1340                 ast_channel_music_state_set(chan, NULL);
1341                 /* Only held a module reference if we had a music state */
1342                 ast_module_unref(ast_module_info->self);
1343         }
1344 }
1345
1346 static void moh_class_destructor(void *obj);
1347
1348 #define moh_class_malloc()      _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)
1349
1350 static struct mohclass *_moh_class_malloc(const char *file, int line, const char *funcname)
1351 {
1352         struct mohclass *class;
1353
1354         if ((class =
1355 #ifdef REF_DEBUG
1356                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1357                                 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 1)
1358 #elif defined(__AST_DEBUG_MALLOC)
1359                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1360                                 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 0)
1361 #else
1362                         ao2_alloc(sizeof(*class), moh_class_destructor)
1363 #endif
1364                 )) {
1365                 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1366                 class->srcfd = -1;
1367         }
1368
1369         return class;
1370 }
1371
1372 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1373 {
1374         struct mohclass *mohclass = NULL;
1375         struct moh_files_state *state = ast_channel_music_state(chan);
1376         struct ast_variable *var = NULL;
1377         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1378         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1379         int res;
1380         int realtime_possible = ast_check_realtime("musiconhold");
1381
1382         /* The following is the order of preference for which class to use:
1383          * 1) The channels explicitly set musicclass, which should *only* be
1384          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1385          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1386          *    result of receiving a HOLD control frame, this should be the
1387          *    payload that came with the frame.
1388          * 3) The interpclass argument. This would be from the mohinterpret
1389          *    option from channel drivers. This is the same as the old musicclass
1390          *    option.
1391          * 4) The default class.
1392          */
1393         if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
1394                 mohclass = get_mohbyname(ast_channel_musicclass(chan), 1, 0);
1395                 if (!mohclass && realtime_possible) {
1396                         var = ast_load_realtime("musiconhold", "name", ast_channel_musicclass(chan), SENTINEL);
1397                 }
1398         }
1399         if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1400                 mohclass = get_mohbyname(mclass, 1, 0);
1401                 if (!mohclass && realtime_possible) {
1402                         var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1403                 }
1404         }
1405         if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1406                 mohclass = get_mohbyname(interpclass, 1, 0);
1407                 if (!mohclass && realtime_possible) {
1408                         var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1409                 }
1410         }
1411
1412         if (!mohclass && !var) {
1413                 mohclass = get_mohbyname("default", 1, 0);
1414                 if (!mohclass && realtime_possible) {
1415                         var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1416                 }
1417         }
1418
1419         /* If no moh class found in memory, then check RT. Note that the logic used
1420          * above guarantees that if var is non-NULL, then mohclass must be NULL.
1421          */
1422         if (var) {
1423                 struct ast_variable *tmp = NULL;
1424
1425                 if ((mohclass = moh_class_malloc())) {
1426                         mohclass->realtime = 1;
1427                         for (tmp = var; tmp; tmp = tmp->next) {
1428                                 if (!strcasecmp(tmp->name, "name"))
1429                                         ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1430                                 else if (!strcasecmp(tmp->name, "mode"))
1431                                         ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
1432                                 else if (!strcasecmp(tmp->name, "directory"))
1433                                         ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1434                                 else if (!strcasecmp(tmp->name, "application"))
1435                                         ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1436                                 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1437                                         mohclass->digit = *tmp->value;
1438                                 else if (!strcasecmp(tmp->name, "random"))
1439                                         ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1440                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1441                                         ast_set_flag(mohclass, MOH_RANDOMIZE);
1442                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
1443                                         ast_set_flag(mohclass, MOH_SORTALPHA);
1444                                 else if (!strcasecmp(tmp->name, "format")) {
1445                                         ast_getformatbyname(tmp->value, &mohclass->format);
1446                                         if (!mohclass->format.id) {
1447                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1448                                                 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
1449                                         }
1450                                 }
1451                         }
1452                         ast_variables_destroy(var);
1453                         if (ast_strlen_zero(mohclass->dir)) {
1454                                 if (!strcasecmp(mohclass->mode, "custom")) {
1455                                         strcpy(mohclass->dir, "nodir");
1456                                 } else {
1457                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1458                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1459                                         return -1;
1460                                 }
1461                         }
1462                         if (ast_strlen_zero(mohclass->mode)) {
1463                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1464                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1465                                 return -1;
1466                         }
1467                         if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1468                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1469                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1470                                 return -1;
1471                         }
1472
1473                         if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1474                                 /* CACHERTCLASSES enabled, let's add this class to default tree */
1475                                 if (state && state->class) {
1476                                         /* Class already exist for this channel */
1477                                         ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1478                                         if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1479                                                 /* we found RT class with the same name, seems like we should continue playing existing one */
1480                                                 /* XXX This code is impossible to reach */
1481                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)");
1482                                                 mohclass = state->class;
1483                                         }
1484                                 }
1485                                 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1486                                  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1487                                  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1488                                  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1489                                  * invalid memory.
1490                                  */
1491                                 if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1492                                         mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1493                                         return -1;
1494                                 }
1495                         } else {
1496                                 /* We don't register RT moh class, so let's init it manualy */
1497
1498                                 time(&mohclass->start);
1499                                 mohclass->start -= respawn_time;
1500
1501                                 if (!strcasecmp(mohclass->mode, "files")) {
1502                                         if (!moh_scan_files(mohclass)) {
1503                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1504                                                 return -1;
1505                                         }
1506                                         if (strchr(mohclass->args, 'r'))
1507                                                 ast_set_flag(mohclass, MOH_RANDOMIZE);
1508                                 } else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) {
1509
1510                                         if (!strcasecmp(mohclass->mode, "custom"))
1511                                                 ast_set_flag(mohclass, MOH_CUSTOM);
1512                                         else if (!strcasecmp(mohclass->mode, "mp3nb"))
1513                                                 ast_set_flag(mohclass, MOH_SINGLE);
1514                                         else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1515                                                 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1516                                         else if (!strcasecmp(mohclass->mode, "quietmp3"))
1517                                                 ast_set_flag(mohclass, MOH_QUIET);
1518
1519                                         mohclass->srcfd = -1;
1520                                         if (!(mohclass->timer = ast_timer_open())) {
1521                                                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1522                                         }
1523                                         if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1524                                                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1525                                                 ast_timer_close(mohclass->timer);
1526                                                 mohclass->timer = NULL;
1527                                         }
1528
1529                                         /* Let's check if this channel already had a moh class before */
1530                                         if (state && state->class) {
1531                                                 /* Class already exist for this channel */
1532                                                 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1533                                                 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1534                                                         /* we found RT class with the same name, seems like we should continue playing existing one */
1535                                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1536                                                         mohclass = state->class;
1537                                                 }
1538                                         } else {
1539                                                 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1540                                                         ast_log(LOG_WARNING, "Unable to create moh...\n");
1541                                                         if (mohclass->timer) {
1542                                                                 ast_timer_close(mohclass->timer);
1543                                                                 mohclass->timer = NULL;
1544                                                         }
1545                                                         mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1546                                                         return -1;
1547                                                 }
1548                                         }
1549                                 } else {
1550                                         ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1551                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1552                                         return -1;
1553                                 }
1554                         }
1555                 } else {
1556                         ast_variables_destroy(var);
1557                         var = NULL;
1558                 }
1559         }
1560
1561         if (!mohclass) {
1562                 return -1;
1563         }
1564
1565         /* If we are using a cached realtime class with files, re-scan the files */
1566         if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1567                 if (!moh_scan_files(mohclass)) {
1568                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1569                         return -1;
1570                 }
1571         }
1572
1573         ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1574
1575         if (mohclass->total_files) {
1576                 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1577         } else {
1578                 res = ast_activate_generator(chan, &mohgen, mohclass);
1579         }
1580
1581         json_object = ast_json_pack("{s: s}",
1582                         "class", mohclass->name);
1583         if (!json_object) {
1584                 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1585                 return -1;
1586         }
1587
1588         message = ast_channel_cached_blob_create(chan,
1589                         ast_channel_moh_start_type(),
1590                         json_object);
1591         if (message) {
1592                 stasis_publish(ast_channel_topic(chan), message);
1593         }
1594
1595         mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1596
1597         return res;
1598 }
1599
1600 static void local_ast_moh_stop(struct ast_channel *chan)
1601 {
1602         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1603         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1604         ast_deactivate_generator(chan);
1605
1606         ast_channel_lock(chan);
1607         if (ast_channel_music_state(chan)) {
1608                 if (ast_channel_stream(chan)) {
1609                         ast_closestream(ast_channel_stream(chan));
1610                         ast_channel_stream_set(chan, NULL);
1611                 }
1612         }
1613
1614         message = ast_channel_cached_blob_create(chan, ast_channel_moh_stop_type(), NULL);
1615         if (message) {
1616                 stasis_publish(ast_channel_topic(chan), message);
1617         }
1618         ast_channel_unlock(chan);
1619 }
1620
1621 static void moh_class_destructor(void *obj)
1622 {
1623         struct mohclass *class = obj;
1624         struct mohdata *member;
1625         pthread_t tid = 0;
1626
1627         ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1628
1629         ao2_lock(class);
1630         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1631                 free(member);
1632         }
1633         ao2_unlock(class);
1634
1635         /* Kill the thread first, so it cannot restart the child process while the
1636          * class is being destroyed */
1637         if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1638                 tid = class->thread;
1639                 class->thread = AST_PTHREADT_NULL;
1640                 pthread_cancel(tid);
1641                 /* We'll collect the exit status later, after we ensure all the readers
1642                  * are dead. */
1643         }
1644
1645         if (class->pid > 1) {
1646                 char buff[8192];
1647                 int bytes, tbytes = 0, stime = 0, pid = 0;
1648
1649                 ast_debug(1, "killing %d!\n", class->pid);
1650
1651                 stime = time(NULL) + 2;
1652                 pid = class->pid;
1653                 class->pid = 0;
1654
1655                 /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1656                  * to give the process a reason and time enough to kill off its
1657                  * children. */
1658                 do {
1659                         if (killpg(pid, SIGHUP) < 0) {
1660                                 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1661                         }
1662                         usleep(100000);
1663                         if (killpg(pid, SIGTERM) < 0) {
1664                                 if (errno == ESRCH) {
1665                                         break;
1666                                 }
1667                                 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1668                         }
1669                         usleep(100000);
1670                         if (killpg(pid, SIGKILL) < 0) {
1671                                 if (errno == ESRCH) {
1672                                         break;
1673                                 }
1674                                 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1675                         }
1676                 } while (0);
1677
1678                 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
1679                                 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1680                         tbytes = tbytes + bytes;
1681                 }
1682
1683                 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1684
1685                 close(class->srcfd);
1686                 class->srcfd = -1;
1687         }
1688
1689         if (class->filearray) {
1690                 int i;
1691                 for (i = 0; i < class->total_files; i++) {
1692                         free(class->filearray[i]);
1693                 }
1694                 free(class->filearray);
1695                 class->filearray = NULL;
1696         }
1697
1698         if (class->timer) {
1699                 ast_timer_close(class->timer);
1700                 class->timer = NULL;
1701         }
1702
1703         /* Finally, collect the exit status of the monitor thread */
1704         if (tid > 0) {
1705                 pthread_join(tid, NULL);
1706         }
1707
1708 }
1709
1710 static int moh_class_mark(void *obj, void *arg, int flags)
1711 {
1712         struct mohclass *class = obj;
1713
1714         class->delete = 1;
1715
1716         return 0;
1717 }
1718
1719 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1720 {
1721         struct mohclass *class = obj;
1722
1723         return class->delete ? CMP_MATCH : 0;
1724 }
1725
1726 static int load_moh_classes(int reload)
1727 {
1728         struct ast_config *cfg;
1729         struct ast_variable *var;
1730         struct mohclass *class; 
1731         char *cat;
1732         int numclasses = 0;
1733         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1734
1735         cfg = ast_config_load("musiconhold.conf", config_flags);
1736
1737         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1738                 if (ast_check_realtime("musiconhold") && reload) {
1739                         ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1740                         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
1741                 }
1742                 return 0;
1743         }
1744         if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1745                 moh_rescan_files();
1746                 return 0;
1747         }
1748
1749         if (reload) {
1750                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1751         }
1752
1753         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1754
1755         cat = ast_category_browse(cfg, NULL);
1756         for (; cat; cat = ast_category_browse(cfg, cat)) {
1757                 /* Setup common options from [general] section */
1758                 if (!strcasecmp(cat, "general")) {
1759                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1760                                 if (!strcasecmp(var->name, "cachertclasses")) {
1761                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1762                                 } else {
1763                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1764                                 }
1765                         }
1766                 }
1767                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1768                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1769                                 !strcasecmp(cat, "general")) {
1770                         continue;
1771                 }
1772
1773                 if (!(class = moh_class_malloc())) {
1774                         break;
1775                 }
1776
1777                 ast_copy_string(class->name, cat, sizeof(class->name));
1778                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1779                         if (!strcasecmp(var->name, "mode")) {
1780                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1781                         } else if (!strcasecmp(var->name, "directory")) {
1782                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1783                         } else if (!strcasecmp(var->name, "application")) {
1784                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1785                         } else if (!strcasecmp(var->name, "announcement")) {
1786                                 ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
1787                                 ast_set_flag(class, MOH_ANNOUNCEMENT);
1788                         } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
1789                                 class->digit = *var->value;
1790                         } else if (!strcasecmp(var->name, "random")) {
1791                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1792                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) {
1793                                 ast_set_flag(class, MOH_RANDOMIZE);
1794                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
1795                                 ast_set_flag(class, MOH_SORTALPHA);
1796                         } else if (!strcasecmp(var->name, "format")) {
1797                                 ast_getformatbyname(var->value, &class->format);
1798                                 if (!class->format.id) {
1799                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1800                                         ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1801                                 }
1802                         }
1803                 }
1804
1805                 if (ast_strlen_zero(class->dir)) {
1806                         if (!strcasecmp(class->mode, "custom")) {
1807                                 strcpy(class->dir, "nodir");
1808                         } else {
1809                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1810                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1811                                 continue;
1812                         }
1813                 }
1814                 if (ast_strlen_zero(class->mode)) {
1815                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1816                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1817                         continue;
1818                 }
1819                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1820                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1821                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1822                         continue;
1823                 }
1824
1825                 /* Don't leak a class when it's already registered */
1826                 if (!moh_register(class, reload, HANDLE_REF)) {
1827                         numclasses++;
1828                 }
1829         }
1830
1831         ast_config_destroy(cfg);
1832
1833         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1834                         moh_classes_delete_marked, NULL, "Purge marked classes");
1835
1836         return numclasses;
1837 }
1838
1839 static void ast_moh_destroy(void)
1840 {
1841         ast_verb(2, "Destroying musiconhold processes\n");
1842         if (mohclasses) {
1843                 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1844                 ao2_ref(mohclasses, -1);
1845                 mohclasses = NULL;
1846         }
1847 }
1848
1849 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1850 {
1851         switch (cmd) {
1852         case CLI_INIT:
1853                 e->command = "moh reload";
1854                 e->usage =
1855                         "Usage: moh reload\n"
1856                         "       Reloads the MusicOnHold module.\n"
1857                         "       Alias for 'module reload res_musiconhold.so'\n";
1858                 return NULL;
1859         case CLI_GENERATE:
1860                 return NULL;
1861         }
1862
1863         if (a->argc != e->args)
1864                 return CLI_SHOWUSAGE;
1865
1866         reload();
1867
1868         return CLI_SUCCESS;
1869 }
1870
1871 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1872 {
1873         struct mohclass *class;
1874         struct ao2_iterator i;
1875
1876         switch (cmd) {
1877         case CLI_INIT:
1878                 e->command = "moh show files";
1879                 e->usage =
1880                         "Usage: moh show files\n"
1881                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1882                         "       files.\n";
1883                 return NULL;
1884         case CLI_GENERATE:
1885                 return NULL;
1886         }
1887
1888         if (a->argc != e->args)
1889                 return CLI_SHOWUSAGE;
1890
1891         i = ao2_iterator_init(mohclasses, 0);
1892         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1893                 int x;
1894
1895                 if (!class->total_files) {
1896                         continue;
1897                 }
1898
1899                 ast_cli(a->fd, "Class: %s\n", class->name);
1900                 for (x = 0; x < class->total_files; x++) {
1901                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1902                 }
1903         }
1904         ao2_iterator_destroy(&i);
1905
1906         return CLI_SUCCESS;
1907 }
1908
1909 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1910 {
1911         struct mohclass *class;
1912         struct ao2_iterator i;
1913
1914         switch (cmd) {
1915         case CLI_INIT:
1916                 e->command = "moh show classes";
1917                 e->usage =
1918                         "Usage: moh show classes\n"
1919                         "       Lists all MusicOnHold classes.\n";
1920                 return NULL;
1921         case CLI_GENERATE:
1922                 return NULL;
1923         }
1924
1925         if (a->argc != e->args)
1926                 return CLI_SHOWUSAGE;
1927
1928         i = ao2_iterator_init(mohclasses, 0);
1929         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1930                 ast_cli(a->fd, "Class: %s\n", class->name);
1931                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1932                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1933                 if (ast_test_flag(class, MOH_CUSTOM)) {
1934                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1935                 }
1936                 if (strcasecmp(class->mode, "files")) {
1937                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
1938                 }
1939         }
1940         ao2_iterator_destroy(&i);
1941
1942         return CLI_SUCCESS;
1943 }
1944
1945 static struct ast_cli_entry cli_moh[] = {
1946         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1947         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1948         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1949 };
1950
1951 static int moh_class_hash(const void *obj, const int flags)
1952 {
1953         const struct mohclass *class = obj;
1954
1955         return ast_str_case_hash(class->name);
1956 }
1957
1958 static int moh_class_cmp(void *obj, void *arg, int flags)
1959 {
1960         struct mohclass *class = obj, *class2 = arg;
1961
1962         return strcasecmp(class->name, class2->name) ? 0 :
1963                 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1964                 CMP_MATCH | CMP_STOP;
1965 }
1966
1967 /*!
1968  * \brief Load the module
1969  *
1970  * Module loading including tests for configuration or dependencies.
1971  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1972  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1973  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
1974  * configuration file or other non-critical problem return 
1975  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1976  */
1977 static int load_module(void)
1978 {
1979         int res;
1980
1981         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1982                 return AST_MODULE_LOAD_DECLINE;
1983         }
1984
1985         if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) {   /* No music classes configured, so skip it */
1986                 ast_log(LOG_WARNING, "No music on hold classes configured, "
1987                                 "disabling music on hold.\n");
1988         } else {
1989                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1990                                 local_ast_moh_cleanup);
1991         }
1992
1993         res = ast_register_application_xml(play_moh, play_moh_exec);
1994         ast_register_atexit(ast_moh_destroy);
1995         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1996         if (!res)
1997                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1998         if (!res)
1999                 res = ast_register_application_xml(set_moh, set_moh_exec);
2000         if (!res)
2001                 res = ast_register_application_xml(start_moh, start_moh_exec);
2002         if (!res)
2003                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
2004
2005         return AST_MODULE_LOAD_SUCCESS;
2006 }
2007
2008 static int reload(void)
2009 {
2010         if (load_moh_classes(1)) {
2011                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
2012                                 local_ast_moh_cleanup);
2013         }
2014
2015         return AST_MODULE_LOAD_SUCCESS;
2016 }
2017
2018 static int moh_class_inuse(void *obj, void *arg, int flags)
2019 {
2020         struct mohclass *class = obj;
2021
2022         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
2023 }
2024
2025 static int unload_module(void)
2026 {
2027         int res = 0;
2028         struct mohclass *class = NULL;
2029
2030         /* XXX This check shouldn't be required if module ref counting was being used
2031          * properly ... */
2032         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
2033                 class = mohclass_unref(class, "unref of class from module unload callback");
2034                 res = -1;
2035         }
2036
2037         if (res < 0) {
2038                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
2039                 return res;
2040         }
2041
2042         ast_uninstall_music_functions();
2043
2044         ast_moh_destroy();
2045         res = ast_unregister_application(play_moh);
2046         res |= ast_unregister_application(wait_moh);
2047         res |= ast_unregister_application(set_moh);
2048         res |= ast_unregister_application(start_moh);
2049         res |= ast_unregister_application(stop_moh);
2050         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
2051         ast_unregister_atexit(ast_moh_destroy);
2052
2053         return res;
2054 }
2055
2056 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
2057         .load = load_module,
2058         .unload = unload_module,
2059         .reload = reload,
2060         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
2061 );